-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Workflow e2e tests – 1st batch #9713
base: main
Are you sure you want to change the base?
Conversation
Deleting an account doesn't clear the user from the database, it just removes the user from the workspace. The test used to fail when ran several times.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR Summary
This PR introduces end-to-end testing for workflow functionality while streamlining the testing infrastructure. The changes focus on workflow creation, visualization, and cleanup operations.
- Added new workflow E2E test suite with
blank-workflow.ts
fixture and corresponding test files for workflow creation and visualization - Removed redundant utility files (
customreporter.ts
,env_variables.ts
,shell_driver.ts
) in favor of built-in Playwright functionality - Added GraphQL request handlers in
/lib/requests/
for workflow CRUD operations with proper authentication - Added data-testid attributes to frontend components to support E2E test selectors
- Simplified environment setup by automating
.env
file creation from example template
21 file(s) reviewed, 24 comment(s)
Edit PR Review Bot Settings | Greptile
# Note that provide always without trailing forward slash to have expected behaviour | ||
FRONTEND_BASE_URL=http://localhost:3001 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: the comment about trailing forward slash is now inconsistent with line 9 which requires a trailing forward slash for REST API
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: This file was deleted without providing an alternative mechanism for setting up test environment variables. Ensure there is a new implementation for managing test environment configuration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: Removing the shell command execution capability could break existing tests or utilities that depend on it. Need confirmation that this functionality is either no longer needed or has been moved elsewhere.
const response = await createWorkflow({ | ||
page: this.#page, | ||
workflowId: id, | ||
workflowName: this.workflowName, | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: no try/catch block around API call could cause test failures to be unclear if API is down
await deleteWorkflow({ | ||
page, | ||
workflowId: workflowVisualizer.workflowId, | ||
}); | ||
await destroyWorkflow({ | ||
page, | ||
workflowId: workflowVisualizer.workflowId, | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: cleanup operations should be in try/finally to ensure they run even if test fails
import { expect } from '@playwright/test'; | ||
import { test } from '../lib/fixtures/blank-workflow'; | ||
|
||
test('Create simple workflow', async ({ workflowVisualizer, page }) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: workflowVisualizer fixture is imported but never used in the test
await expect( | ||
page.getByTestId('command-menu').getByRole('textbox'), | ||
).toHaveValue('When a Company is Created'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: add a timeout to this expectation since command menu may take time to populate
await expect(triggerNode).toHaveClass(/selected/); | ||
await expect(triggerNode).toHaveText(/Company is Created/); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: use exact text matching with triggerNode.toHaveText() to ensure precise validation
const createRecordNode = page | ||
.locator('.react-flow__node.selected') | ||
.getByText('Create Record'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: locating by CSS class '.react-flow__node.selected' is fragile - consider using a data-testid instead
@@ -15,7 +15,7 @@ export const WorkflowDiagramCreateStepNode = () => { | |||
<StyledContainer> | |||
<StyledTargetHandle type="target" position={Position.Top} /> | |||
|
|||
<IconButton Icon={IconPlus} size="medium" /> | |||
<IconButton Icon={IconPlus} size="medium" ariaLabel="Add a step" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
syntax: The prop should be 'aria-label' instead of 'ariaLabel' to follow standard HTML accessibility attribute naming
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really nice! Scenario LGTM. Can you check with someone who knows end to end tests setup?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's very good !
Interesting scenarios and tests cleanups
It seems like there're two directions of describing tests
We should take a decision regarding the Page Object Model
abstraction degree of integration we wanna reach to
In my best of the world, tests scenario reports should be readable by anyone, not necessary a tech. I mean any product team mate that has access to a playwright report should be able to interpret the result of a scenario failure, in order to produce a exhaustive backlog/issue.
That's the first time I'm reviewing the twenty-e2e-testing
package, I'm not a Playwright
expert at all, below can be found a list of things I think we could try to improve regarding the package as whole and not necessary this PR diff:
- Typing and validating
process.env
- Typecheck
twenty-e2e-testing
package in theci
- setup webDevServer in order to simplify and centralize building logic locally and in the
ci
- Define a file tree architecture, regarding fixture localization and so on and use absolute imports
- Add
.nx
caching in e2e ci - Publish and version playwright reports, e.g on a static website
if (!authCookie) { | ||
throw new Error('No auth cookie found'); | ||
} | ||
const token = JSON.parse(decodeURIComponent(authCookie.value)).accessToken |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: Token is any
here
@@ -8,7 +8,8 @@ | |||
"options": { | |||
"cwd": "packages/twenty-e2e-testing", | |||
"commands": [ | |||
"yarn playwright install" | |||
"yarn playwright install", | |||
"cp .env.example .env" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Praise: Good idea, about what greptile
says I think this might even be a better behavior as for the moment we don't any env variables that needs a user prompt.
import { deleteWorkflow } from '../lib/requests/delete-workflow'; | ||
import { destroyWorkflow } from '../lib/requests/destroy-workflow'; | ||
|
||
test('Create workflow', async ({ page }) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remark: I think in a more Page Object Model
oriented vision this could result from interaction with the workflow Page
import { test } from '../lib/fixtures/blank-workflow'; | ||
|
||
test('Create simple workflow', async ({ workflowVisualizer, page }) => { | ||
const addTriggerButton = page.getByText('Add a Trigger'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: Unused workflowVisualizer
destructured args
Nitpick: filename workflow-visualizer.spec.ts
, in my opinion, does not really relate the test's business core
@@ -30,35 +30,24 @@ export default defineConfig({ | |||
screenshot: 'on', // either 'on' here or in different method in modules, if 'on' all screenshots are overwritten each time the test is run | |||
headless: true, // instead of changing it to false, run 'yarn test:e2e:debug' or 'yarn test:e2e:ui' | |||
testIdAttribute: 'data-testid', // taken from Twenty source | |||
viewport: { width: 1920, height: 1080 }, // most laptops use this resolution | |||
launchOptions: { | |||
slowMo: 500, // time in milliseconds between each step, better to use it than explicitly define timeout in tests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Praise: 👀
chrome
project relying on asetup
project to get an authentication state which all tests can reuseSign up with invite link via email
test:Create workflow
, a test asserting we can create a workflow from the record tableCreate simple workflow
, a test asserting we can create a simple flow; I will add more assertions to this test and write other tests once this first PR is approvedgetByRole('textbox')
– and I preferred to scope them to a root elementaria-label
to a button