diff --git a/src/execution-flow/flows/clickon-flow.ts b/src/execution-flow/flows/clickon-flow.ts index 2a9b2a2..caa590f 100644 --- a/src/execution-flow/flows/clickon-flow.ts +++ b/src/execution-flow/flows/clickon-flow.ts @@ -1,38 +1,59 @@ -import { spinner } from "@clack/prompts"; import { ElementNotFoundError } from "@src/errors/workflow-error"; import type { BaseFlowParam } from "@type/base-flow.types"; import type { ClickAction } from "@type/workflow-config.types"; -import chalk from "chalk"; import type { Locator } from "playwright"; +import { createFlow } from "./create-flow"; -export default async function clickonFlow({ - step: clickOnStep, - page, -}: BaseFlowParam): Promise { - const clickSpinner = spinner(); +function clickOnDescription(step: ClickAction) { + let targetDescription: `text: ${string}` | `selector: ${string}`; + if (typeof step.clickOn === "string") { + targetDescription = `text: ${step.clickOn}`; + } else { + targetDescription = `selector: ${step.clickOn.selector}`; + } + return targetDescription; +} +function clickOnLocator({ page, step }: BaseFlowParam): Locator { let targetLocator: Locator; - let targetDescription: `text: ${string}` | `selector: ${string}`; - if (typeof clickOnStep.clickOn === "string") { - targetLocator = page.getByText(clickOnStep.clickOn).first(); - targetDescription = `text: ${clickOnStep.clickOn}`; + if (typeof step.clickOn === "string") { + targetLocator = page.getByText(step.clickOn).first(); } else { - targetLocator = page.locator(clickOnStep.clickOn.selector); - targetDescription = `selector: ${clickOnStep.clickOn.selector}`; + targetLocator = page.locator(step.clickOn.selector); } - clickSpinner.start(`Clicking on element with ${targetDescription}`); + return targetLocator; +} + +const clickOnFlow = createFlow({ + action: "clickOn", + + setLoadingMessage: (step) => { + const targetDescription = clickOnDescription(step); + return `Clicking on element with ${targetDescription}`; + }, + + execute: async (params) => { + const targetLocator = clickOnLocator(params); - try { await targetLocator.click(); - clickSpinner.stop( - `${chalk.green("✓")} Clicked on element with ${targetDescription}`, - ); - } catch { - clickSpinner.stop( - `${chalk.red("✖")} clickOn: Unable to find element with ${targetDescription}`, - ); - throw new ElementNotFoundError(`Element missing: ${targetDescription}`); - } -} + }, + + setSuccessMessage: (step) => { + const targetDescription = clickOnDescription(step); + return `Clicked on element with ${targetDescription}`; + }, + + setErrorMessage: (step) => { + const targetDescription = clickOnDescription(step); + return `clickOn: Unable to find element with ${targetDescription}`; + }, + + onError: (_, step) => { + const targetDescription = clickOnDescription(step); + return new ElementNotFoundError(`Element missing: ${targetDescription}`); + }, +}); + +export default clickOnFlow; diff --git a/src/execution-flow/flows/create-flow.ts b/src/execution-flow/flows/create-flow.ts new file mode 100644 index 0000000..f50da68 --- /dev/null +++ b/src/execution-flow/flows/create-flow.ts @@ -0,0 +1,60 @@ +import { spinner } from "@clack/prompts"; +import type { BaseFlowParam } from "@type/base-flow.types"; +import type { FlowStep } from "@type/workflow-config.types"; +import chalk from "chalk"; +import type { StepKeys } from "../flow-registry"; + +export interface FlowConfig { + /** The action name (e.g., 'clickOn', 'input') */ + action: StepKeys; + + /** Generate descriptive message for spinner */ + setLoadingMessage: (step: T) => string; + + /** Core execution logic */ + execute: (params: BaseFlowParam) => Promise; + + /** Custom error handler */ + onError?: (error: unknown, step: T) => Error; + + /** Custom error message for stop spinner (defaults to getMessage) */ + setErrorMessage?: (step: T) => string; + + /** Custom success message for stop spinner (defaults to getMessage) */ + setSuccessMessage?: (step: T) => string; +} + +export function createFlow({ + action, + execute, + setLoadingMessage: getMessage, + setSuccessMessage: getSuccessMessage, + onError, + setErrorMessage: getErrorMessage, +}: FlowConfig) { + return async ({ page, step }: BaseFlowParam): Promise => { + const flowSpinner = spinner(); + const message = getMessage(step); + + flowSpinner.start(message); + + try { + await execute({ step, page }); + + const successMsg = getSuccessMessage ? getSuccessMessage(step) : message; + + flowSpinner.stop(`${chalk.green("✓")} ${successMsg}`); + } catch (error) { + const errorMsg = getErrorMessage + ? getErrorMessage(step) + : `${action}: ${message}`; + flowSpinner.stop(`${chalk.red("✖")} ${errorMsg}`); + + if (onError) { + throw onError(error, step); + } + + throw error; + } + }; +} diff --git a/src/execution-flow/flows/input-flow.ts b/src/execution-flow/flows/input-flow.ts index f28f726..3f6f93d 100644 --- a/src/execution-flow/flows/input-flow.ts +++ b/src/execution-flow/flows/input-flow.ts @@ -1,68 +1,109 @@ -import { spinner } from "@clack/prompts"; import type { BaseFlowParam } from "@type/base-flow.types"; import type { Role } from "@type/role.types"; import type { InputAction } from "@type/workflow-config.types"; -import chalk from "chalk"; +import type { Locator } from "playwright"; +import { createFlow } from "./create-flow"; -export default async function inputFlow({ - step: inputStep, - page, -}: BaseFlowParam): Promise { - const inputSelector = inputStep.input.selector; - const inputSpinner = spinner(); - inputSpinner.start(`Filling input: ${inputSelector}`); - if (inputSelector.startsWith("label:")) { - const labelText = inputSelector.replace("label:", "").trim(); - await page - .getByLabel(labelText) - .fill(inputStep.input.value) - .then(() => { - inputSpinner.stop( - `${chalk.green("✓")} Filled input for label: ${labelText}`, - ); - }); - } else if (inputSelector.startsWith("testID:")) { - const id = inputSelector.replace("testID:", "").trim(); - await page - .getByTestId(id) - .fill(inputStep.input.value) - .then(() => { - inputSpinner.stop(`${chalk.green("✓")}Filled input for testID: ${id}`); - }); - } else if (inputSelector.startsWith("placeholder:")) { - const placeholderText = inputSelector.replace("placeholder:", "").trim(); - await page - .getByPlaceholder(placeholderText) - .fill(inputStep.input.value) - .then(() => { - inputSpinner.stop( - `${chalk.green( - "✓", - )} Filled input for placeholder: ${placeholderText}`, - ); - }); - } else if (inputSelector.startsWith("role:")) { - const roleAndName = inputSelector.replace("role:", "").trim(); - const [role, ...nameParts] = roleAndName.split(" "); - const name = nameParts.join(" ").replace('name="', "").replace('"', ""); - await page - .getByRole(role as Role, { name }) - .fill(inputStep.input.value) - .then(() => { - inputSpinner.stop( - `${chalk.green( - "✓", - )} Filled input for role: ${role} and name: ${name}`, - ); - }); - } else { - await page - .locator(inputSelector) - .fill(inputStep.input.value) - .then(() => { - inputSpinner.stop( - `${chalk.green("✓")} Filled input for selector: ${inputSelector}`, - ); +type Action = "label" | "testID" | "placeholder" | "role" | "selector"; + +type InputValueProp = { + action: Action; + step: InputAction; +}; + +type InputValue = + | { action: Exclude; value: string } + | { + action: Extract; + value: { role: string; name: string }; + }; + +function inputValue({ action, step }: InputValueProp): InputValue { + const inputSelector = step.input.selector; + + switch (action) { + case "label": { + const labelText = inputSelector.replace("label:", "").trim(); + return { action: "label", value: labelText }; + } + case "placeholder": { + const placeholderText = inputSelector.replace("placeholder:", "").trim(); + return { action: "placeholder", value: placeholderText }; + } + case "role": { + const roleAndName = inputSelector.replace("role:", "").trim(); + const [role, ...nameParts] = roleAndName.split(" "); + const name = nameParts.join(" ").replace('name="', "").replace('"', ""); + return { action: "role", value: { name, role } }; + } + case "selector": { + return { action: "selector", value: inputSelector }; + } + case "testID": { + const id = inputSelector.replace("testID:", "").trim(); + return { action: "testID", value: id }; + } + default: + return { action: "selector", value: inputSelector }; + } +} + +function getActionType(selector: string): Action { + if (selector.startsWith("label:")) return "label"; + if (selector.startsWith("testID:")) return "testID"; + if (selector.startsWith("placeholder:")) return "placeholder"; + if (selector.startsWith("role:")) return "role"; + return "selector"; +} + +function inputDescription(step: InputAction): string { + const actionType = getActionType(step.input.selector); + const result = inputValue({ action: actionType, step }); + + switch (result.action) { + case "label": + return `label: ${result.value}`; + case "testID": + return `testID: ${result.value}`; + case "placeholder": + return `placeholder: ${result.value}`; + case "role": + return `role: ${result.value.role} and name: ${result.value.name}`; + default: + return `selector: ${result.value}`; + } +} + +function inputLocator({ page, step }: BaseFlowParam): Locator { + const actionType = getActionType(step.input.selector); + const result = inputValue({ action: actionType, step }); + + switch (result.action) { + case "label": + return page.getByLabel(result.value); + case "testID": + return page.getByTestId(result.value); + case "placeholder": + return page.getByPlaceholder(result.value); + case "role": + return page.getByRole(result.value.role as Role, { + name: result.value.name, }); + default: + return page.locator(result.value); } } + +export const inputFlow = createFlow({ + action: "input", + async execute({ page, step }) { + const locator = inputLocator({ page, step }); + await locator.fill(step.input.value); + }, + setLoadingMessage(step) { + const target = inputDescription(step); + return `Filling input for ${target}`; + }, +}); + +export default inputFlow; diff --git a/src/execution-flow/flows/is-disabled-flow.ts b/src/execution-flow/flows/is-disabled-flow.ts index 016288a..b3fc48b 100644 --- a/src/execution-flow/flows/is-disabled-flow.ts +++ b/src/execution-flow/flows/is-disabled-flow.ts @@ -1,40 +1,58 @@ -import { spinner } from "@clack/prompts"; import { FailedAssertionError } from "@src/errors/workflow-error"; import type { BaseFlowParam } from "@type/base-flow.types"; import type { IsDisabledAction } from "@type/workflow-config.types"; -import chalk from "chalk"; import type { Locator } from "playwright"; import { expect } from "playwright/test"; +import { createFlow } from "./create-flow"; -export default async function isDisabledFlow({ - step: isDisabledStep, - page, -}: BaseFlowParam): Promise { - const isDisabledSpinner = spinner(); - let targetLocator: Locator; +function isDisableDescription(step: IsDisabledAction): string { let targetDescription: `text: ${string}` | `selector: ${string}`; - if (typeof isDisabledStep.isDisabled === "string") { - targetLocator = page.getByText(isDisabledStep.isDisabled).first(); - targetDescription = `text: ${isDisabledStep.isDisabled}`; + if (typeof step.isDisabled === "string") { + targetDescription = `text: ${step.isDisabled}`; } else { - targetLocator = page.locator(isDisabledStep.isDisabled.selector); - targetDescription = `selector: ${isDisabledStep.isDisabled.selector}`; + targetDescription = `selector: ${step.isDisabled.selector}`; } + return targetDescription; +} - isDisabledSpinner.start( - `Checking visibility of element with ${targetDescription}`, - ); +function isDisabledLocator({ + page, + step, +}: BaseFlowParam): Locator { + let targetLocator: Locator; - try { - await expect(targetLocator).toBeDisabled(); - isDisabledSpinner.stop( - `${chalk.green("✓")} Element is disabled with ${targetDescription}`, - ); - } catch { - isDisabledSpinner.stop( - `${chalk.red("✖")} isDisabled: Element is not disabled with ${targetDescription}`, - ); - throw new FailedAssertionError(`Assertion failed: ${targetDescription}`); + if (typeof step.isDisabled === "string") { + targetLocator = page.getByText(step.isDisabled).first(); + } else { + targetLocator = page.locator(step.isDisabled.selector); } + + return targetLocator; } + +const isDisabledFlow = createFlow({ + action: "isDisabled", + setLoadingMessage(step) { + const targetDescription = isDisableDescription(step); + return `Checking visibility of element with ${targetDescription}`; + }, + async execute(params) { + const targetLocator = isDisabledLocator(params); + await expect(targetLocator).toBeDisabled(); + }, + setSuccessMessage(step) { + const targetDescription = isDisableDescription(step); + return `Element is disabled with ${targetDescription}`; + }, + setErrorMessage(step) { + const targetDescription = isDisableDescription(step); + return `isDisabled: Element is not disabled with ${targetDescription}`; + }, + onError(_, step) { + const targetDescription = isDisableDescription(step); + return new FailedAssertionError(`Assertion failed: ${targetDescription}`); + }, +}); + +export default isDisabledFlow; diff --git a/src/execution-flow/flows/is-not-visible-flow.ts b/src/execution-flow/flows/is-not-visible-flow.ts index 5834b1b..bc5dbca 100644 --- a/src/execution-flow/flows/is-not-visible-flow.ts +++ b/src/execution-flow/flows/is-not-visible-flow.ts @@ -1,41 +1,59 @@ -import { spinner } from "@clack/prompts"; import { FailedAssertionError } from "@src/errors/workflow-error"; import type { BaseFlowParam } from "@type/base-flow.types"; import type { IsNotVisibleAction } from "@type/workflow-config.types"; -import chalk from "chalk"; import type { Locator } from "playwright"; import { expect } from "playwright/test"; +import { createFlow } from "./create-flow"; -export default async function isNotVisibleFlow({ - step: isNotVisibleStep, +function isNotVisibleDescription( + step: IsNotVisibleAction, +): `text: ${string}` | `selector: ${string}` { + if (typeof step.isNotVisible === "string") { + return `text: ${step.isNotVisible}`; + } + return `selector: ${step.isNotVisible.selector}`; +} + +function isNotVisibleLocator({ page, -}: BaseFlowParam) { - const isNotVisibleSpiner = spinner(); - - let targetLocator: Locator; - let targetDescription: `text: ${string}` | `selector: ${string}`; - - if (typeof isNotVisibleStep.isNotVisible === "string") { - targetLocator = page.getByText(isNotVisibleStep.isNotVisible).first(); - targetDescription = `text: ${isNotVisibleStep.isNotVisible}`; - } else { - targetLocator = page.locator(isNotVisibleStep.isNotVisible.selector); - targetDescription = `selector: ${isNotVisibleStep.isNotVisible.selector}`; + step, +}: BaseFlowParam): Locator { + if (typeof step.isNotVisible === "string") { + return page.getByText(step.isNotVisible).first(); } + return page.locator(step.isNotVisible.selector); +} - isNotVisibleSpiner.start( - `Checking non-visibility of element with ${targetDescription}`, - ); +export const isNotVisibleFlow = createFlow({ + action: "isNotVisible", - try { - await expect(targetLocator).toBeHidden(); - isNotVisibleSpiner.stop( - `${chalk.green("✓")} Element is not visible with ${targetDescription}`, - ); - } catch { - isNotVisibleSpiner.stop( - `${chalk.red("✖")} isNotVisible: Element is visible with ${targetDescription}`, + setLoadingMessage: (step) => { + const targetDescription = isNotVisibleDescription(step); + return `Checking non-visibility of element with ${targetDescription}`; + }, + + execute: async ({ page, step }) => { + const locator = isNotVisibleLocator({ page, step }); + // Usually expect(...).toBeHidden() is what we want for "isNotVisible" + await expect(locator).toBeHidden(); + }, + + setSuccessMessage: (step) => { + const targetDescription = isNotVisibleDescription(step); + return `Element is not visible with ${targetDescription}`; + }, + + setErrorMessage: (step) => { + const targetDescription = isNotVisibleDescription(step); + return `isNotVisible: Element is visible with ${targetDescription}`; + }, + + onError: (error, step) => { + const targetDescription = isNotVisibleDescription(step); + throw new FailedAssertionError( + `Assertion failed: ${targetDescription}. Reason: ${error instanceof Error ? error.message : "unknown"}`, ); - throw new FailedAssertionError(`Assertion failed: ${targetDescription}`); - } -} + }, +}); + +export default isNotVisibleFlow; diff --git a/src/execution-flow/flows/istitle-flow.ts b/src/execution-flow/flows/istitle-flow.ts index e198edc..725b44d 100644 --- a/src/execution-flow/flows/istitle-flow.ts +++ b/src/execution-flow/flows/istitle-flow.ts @@ -1,34 +1,32 @@ -import { spinner } from "@clack/prompts"; import { FailedAssertionError } from "@src/errors/workflow-error"; -import type { BaseFlowParam } from "@type/base-flow.types"; import type { IsTitleAction } from "@type/workflow-config.types"; import regexOrStringMaker from "@utils/regex-or-string-maker"; -import chalk from "chalk"; import { expect } from "playwright/test"; +import { createFlow } from "./create-flow"; -export default async function isTitleFlow({ - step: isTitleStep, - page, -}: BaseFlowParam) { - const isTitleSpinner = spinner(); - - const { isRegex, value: titleOrRegex } = regexOrStringMaker( - isTitleStep.isTitle, - ); - - const LocatorDescription = isRegex ? "Regex:" : "Text:"; - - isTitleSpinner.start(`Checking visibility of page title ${titleOrRegex}`); - - try { +const isTitleFlow = createFlow({ + action: "isTitle", + async execute({ page, step }) { + const { value: titleOrRegex } = regexOrStringMaker(step.isTitle); await expect(page).toHaveTitle(titleOrRegex); - isTitleSpinner.stop( - `${chalk.green("✓")} Page title is visible with ${LocatorDescription} "${titleOrRegex}"`, - ); - } catch { - isTitleSpinner.stop( - `${chalk.red("✖")} isTitle: Page title is not visible with ${LocatorDescription} "${titleOrRegex}"`, - ); - throw new FailedAssertionError(`Assertion failed: ${titleOrRegex}`); - } -} + }, + setLoadingMessage(step) { + const { value: titleOrRegex } = regexOrStringMaker(step.isTitle); + return `Checking visibility of page title ${titleOrRegex}`; + }, + setSuccessMessage(step) { + const { isRegex, value: titleOrRegex } = regexOrStringMaker(step.isTitle); + const LocatorDescription = isRegex ? "Regex:" : "Text:"; + return `Page title is visible with ${LocatorDescription} "${titleOrRegex}"`; + }, + setErrorMessage(step) { + const { isRegex, value: titleOrRegex } = regexOrStringMaker(step.isTitle); + const LocatorDescription = isRegex ? "Regex:" : "Text:"; + return `isTitle: Page title is not visible with ${LocatorDescription} "${titleOrRegex}"`; + }, + onError(_, step) { + const { value: titleOrRegex } = regexOrStringMaker(step.isTitle); + return new FailedAssertionError(`Assertion failed: ${titleOrRegex}`); + }, +}); +export default isTitleFlow; diff --git a/src/execution-flow/flows/isurl-flow.ts b/src/execution-flow/flows/isurl-flow.ts index 69842e2..a36be72 100644 --- a/src/execution-flow/flows/isurl-flow.ts +++ b/src/execution-flow/flows/isurl-flow.ts @@ -1,32 +1,39 @@ -import { spinner } from "@clack/prompts"; import { FailedAssertionError } from "@src/errors/workflow-error"; -import type { BaseFlowParam } from "@type/base-flow.types"; import type { IsURLAction } from "@type/workflow-config.types"; import regexOrStringMaker from "@utils/regex-or-string-maker"; -import chalk from "chalk"; import { expect } from "playwright/test"; +import { createFlow } from "./create-flow"; -export default async function isURLFlow({ - step: isURLStep, - page, -}: BaseFlowParam) { - const isTitleSpinner = spinner(); +const isURLFlow = createFlow({ + action: "isURL", - const { isRegex, value: titleOrRegex } = regexOrStringMaker(isURLStep.isURL); + setLoadingMessage(step) { + const { value: titleOrRegex } = regexOrStringMaker(step.isURL); + return `Checking visibility of page URL ${titleOrRegex}`; + }, - const LocatorDescription = isRegex ? "Regex:" : "URL:"; + async execute({ page, step }) { + const { value: titleOrRegex } = regexOrStringMaker(step.isURL); + await expect(page).toHaveURL(titleOrRegex); + }, - isTitleSpinner.start(`Checking visibility of page URL ${titleOrRegex}`); + setSuccessMessage(step) { + const { isRegex, value: titleOrRegex } = regexOrStringMaker(step.isURL); + const LocatorDescription = isRegex ? "Regex:" : "URL:"; - try { - await expect(page).toHaveURL(titleOrRegex); - isTitleSpinner.stop( - `${chalk.green("✓")} Page URL is visible with ${LocatorDescription} "${titleOrRegex}"`, - ); - } catch { - isTitleSpinner.stop( - `${chalk.red("✖")} isTitle: Page URL is not visible with ${LocatorDescription} "${titleOrRegex}"`, - ); - throw new FailedAssertionError(`Assertion failed: ${titleOrRegex}`); - } -} + return `Page URL is visible with ${LocatorDescription} "${titleOrRegex}"`; + }, + + setErrorMessage(step) { + const { isRegex, value: titleOrRegex } = regexOrStringMaker(step.isURL); + const LocatorDescription = isRegex ? "Regex:" : "URL:"; + return `isURL: Page URL does not match ${LocatorDescription} "${titleOrRegex}"`; + }, + + onError(_, step) { + const { value: titleOrRegex } = regexOrStringMaker(step.isURL); + return new FailedAssertionError(`Assertion failed: ${titleOrRegex}`); + }, +}); + +export default isURLFlow; diff --git a/src/execution-flow/flows/isvisible-flow.ts b/src/execution-flow/flows/isvisible-flow.ts index 5fd9ea0..104a269 100644 --- a/src/execution-flow/flows/isvisible-flow.ts +++ b/src/execution-flow/flows/isvisible-flow.ts @@ -1,41 +1,57 @@ -import { spinner } from "@clack/prompts"; import { FailedAssertionError } from "@src/errors/workflow-error"; import type { BaseFlowParam } from "@type/base-flow.types"; import type { IsVisibleAction } from "@type/workflow-config.types"; -import chalk from "chalk"; import type { Locator } from "playwright"; import { expect } from "playwright/test"; +import { createFlow } from "./create-flow"; -export default async function isVisibleFlow({ - step: isVisibleStep, - page, -}: BaseFlowParam): Promise { - const isVisibleSpiner = spinner(); +function isVisibleDescription(step: IsVisibleAction): string { + let targetDescription: `text: ${string}` | `selector: ${string}`; + if (typeof step.isVisible === "string") { + targetDescription = `text: ${step.isVisible}`; + } else { + targetDescription = `selector: ${step.isVisible.selector}`; + } + return targetDescription; +} +function isVisibleLocator({ + page, + step, +}: BaseFlowParam): Locator { let targetLocator: Locator; - let targetDescription: `text: ${string}` | `selector: ${string}`; - if (typeof isVisibleStep.isVisible === "string") { - targetLocator = page.getByText(isVisibleStep.isVisible).first(); - targetDescription = `text: ${isVisibleStep.isVisible}`; + if (typeof step.isVisible === "string") { + targetLocator = page.getByText(step.isVisible).first(); } else { - targetLocator = page.locator(isVisibleStep.isVisible.selector); - targetDescription = `selector: ${isVisibleStep.isVisible.selector}`; + targetLocator = page.locator(step.isVisible.selector); } - isVisibleSpiner.start( - `Checking visibility of element with ${targetDescription}`, - ); + return targetLocator; +} - try { +const isVisibleFlow = createFlow({ + action: "isVisible", + setLoadingMessage(step) { + const targetDescription = isVisibleDescription(step); + return `Checking visibility of element with ${targetDescription}`; + }, + async execute(params) { + const targetLocator = isVisibleLocator(params); await expect(targetLocator).toBeVisible(); - isVisibleSpiner.stop( - `${chalk.green("✓")} Element is visible with ${targetDescription}`, - ); - } catch { - isVisibleSpiner.stop( - `${chalk.red("✖")} isVisible: Element is not visible with ${targetDescription}`, - ); - throw new FailedAssertionError(`Assertion failed: ${targetDescription}`); - } -} + }, + setSuccessMessage(step) { + const targetDescription = isVisibleDescription(step); + return ` Element is visible with ${targetDescription}`; + }, + setErrorMessage(step) { + const targetDescription = isVisibleDescription(step); + return `isVisible: Element is not visible with ${targetDescription}`; + }, + onError(_, step) { + const targetDescription = isVisibleDescription(step); + return new FailedAssertionError(`Assertion failed: ${targetDescription}`); + }, +}); + +export default isVisibleFlow; diff --git a/src/execution-flow/flows/keyboard-flow.ts b/src/execution-flow/flows/keyboard-flow.ts index 915bc07..7f22a84 100644 --- a/src/execution-flow/flows/keyboard-flow.ts +++ b/src/execution-flow/flows/keyboard-flow.ts @@ -1,16 +1,17 @@ -import { spinner } from "@clack/prompts"; -import type { BaseFlowParam } from "@type/base-flow.types"; import type { KeyboardAction } from "@type/workflow-config.types"; -import chalk from "chalk"; +import { createFlow } from "./create-flow"; -export default async function keyboardFlow({ - step: keyboardStep, - page, -}: BaseFlowParam): Promise { - const keyboardSpinner = spinner(); - keyboardSpinner.start(`Pressing key: ${keyboardStep.keyboard.key}`); - await page.keyboard.press(keyboardStep.keyboard.key); - keyboardSpinner.stop( - `${chalk.green("✓")} Pressed key: ${keyboardStep.keyboard.key}`, - ); -} +const keyboardFlow = createFlow({ + action: "keyboard", + setLoadingMessage(step) { + return `Pressing key: ${step.keyboard.key}`; + }, + async execute({ page, step }) { + await page.keyboard.press(step.keyboard.key); + }, + setSuccessMessage(step) { + return `Pressed key: ${step.keyboard.key}`; + }, +}); + +export default keyboardFlow; diff --git a/src/execution-flow/flows/waitfor-flow.ts b/src/execution-flow/flows/waitfor-flow.ts index 86a3d0a..1d192f5 100644 --- a/src/execution-flow/flows/waitfor-flow.ts +++ b/src/execution-flow/flows/waitfor-flow.ts @@ -1,16 +1,17 @@ -import { spinner } from "@clack/prompts"; -import type { BaseFlowParam } from "@type/base-flow.types"; import type { WaitForAction } from "@type/workflow-config.types"; -import chalk from "chalk"; +import { createFlow } from "./create-flow"; -export default async function waitforFlow({ - step: waitforStep, - page, -}: BaseFlowParam): Promise { - const waitForSpinner = spinner(); - waitForSpinner.start(`Waiting for: ${waitforStep.waitFor.duration}ms`); - await page.waitForTimeout(waitforStep.waitFor.duration); - waitForSpinner.stop( - `${chalk.green("✓")} Waited for: ${waitforStep.waitFor.duration}ms`, - ); -} +const waitforFlow = createFlow({ + action: "waitFor", + setLoadingMessage(step) { + return `Waiting for: ${step.waitFor.duration}ms`; + }, + async execute({ step, page }) { + await page.waitForTimeout(step.waitFor.duration); + }, + setSuccessMessage(step) { + return `Waited for: ${step.waitFor.duration}ms`; + }, +}); + +export default waitforFlow;