Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into fix/advanced-mode-s…
Browse files Browse the repository at this point in the history
…mooth-animation
  • Loading branch information
ehconitin committed Jan 23, 2025
2 parents cf47951 + 337b6a8 commit 4dd1551
Show file tree
Hide file tree
Showing 634 changed files with 8,942 additions and 5,385 deletions.
10 changes: 4 additions & 6 deletions .github/workflows/ci-e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,12 @@ jobs:
- name: Build twenty-shared
run: npx nx build twenty-shared

- name: Install Playwright Browsers
run: npx nx setup twenty-e2e-testing

- name: Setup environment files
run: |
cp packages/twenty-e2e-testing/.env.example packages/twenty-e2e-testing/.env
cp packages/twenty-front/.env.example packages/twenty-front/.env
cp packages/twenty-e2e-testing/.env.example packages/twenty-e2e-testing/.env
npx nx reset:env twenty-server
- name: Build frontend
Expand All @@ -87,7 +88,7 @@ jobs:
PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d postgres -c 'CREATE DATABASE "default";'
PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d postgres -c 'CREATE DATABASE "test";'
npx nx run twenty-server:database:reset
- name: Start server
run: |
npx nx start twenty-server &
Expand All @@ -105,9 +106,6 @@ jobs:
npx nx run twenty-server:worker:ci &
echo "Worker started"
- name: Install Playwright Browsers
run: npx nx setup twenty-e2e-testing

- name: Run Playwright tests
run: npx nx test twenty-e2e-testing

Expand Down
13 changes: 13 additions & 0 deletions .github/workflows/ci-server.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,19 @@ jobs:
exit 1
fi
- name: GraphQL / Check for Pending Generation
if: steps.changed-files.outputs.any_changed == 'true'
run: |
GRAPHQL_GENERATE_OUTPUT=$(npx nx run twenty-front:graphql:generate || true)
GRAPHQL_METADATA_OUTPUT=$(npx nx run twenty-front:graphql:generate --configuration=metadata || true)
if [[ $GRAPHQL_GENERATE_OUTPUT == *"No changes detected"* && $GRAPHQL_METADATA_OUTPUT == *"No changes detected"* ]]; then
echo "GraphQL generation check passed."
else
echo "::error::Unexpected GraphQL changes detected. Please run the required commands and commit the changes."
echo "$GRAPHQL_GENERATE_OUTPUT"
echo "$GRAPHQL_METADATA_OUTPUT"
exit 1
fi
- name: Save server setup
uses: ./.github/workflows/actions/save-cache
with:
Expand Down
4 changes: 2 additions & 2 deletions packages/twenty-chrome-extension/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
"skipLibCheck": true,
"esModuleInterop": true,
"paths": {
"@/*": ["packages/twenty-chrome-extension/src/options/modules/*"],
"~/*": ["packages/twenty-chrome-extension/src/*"]
"@/*": ["./src/options/modules/*"],
"~/*": ["./src/*"]
},

/* Bundler mode */
Expand Down
1 change: 1 addition & 0 deletions packages/twenty-e2e-testing/.env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Note that provide always without trailing forward slash to have expected behaviour
FRONTEND_BASE_URL=http://localhost:3001
BACKEND_BASE_URL=http://localhost:3000
DEFAULT_LOGIN=[email protected]
DEFAULT_PASSWORD=Applecar2025
WEBSITE_URL=https://twenty.com
Expand Down
33 changes: 0 additions & 33 deletions packages/twenty-e2e-testing/config/customreporter.ts

This file was deleted.

21 changes: 0 additions & 21 deletions packages/twenty-e2e-testing/drivers/env_variables.ts

This file was deleted.

13 changes: 0 additions & 13 deletions packages/twenty-e2e-testing/drivers/shell_driver.ts

This file was deleted.

249 changes: 249 additions & 0 deletions packages/twenty-e2e-testing/lib/fixtures/blank-workflow.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
import { test as base, expect, Locator, Page } from '@playwright/test';
import { randomUUID } from 'node:crypto';
import { createWorkflow } from '../requests/create-workflow';
import { deleteWorkflow } from '../requests/delete-workflow';
import { destroyWorkflow } from '../requests/destroy-workflow';
import { WorkflowActionType, WorkflowTriggerType } from '../types/workflows';

export class WorkflowVisualizerPage {
#page: Page;

workflowId: string;
workflowName: string;

readonly addStepButton: Locator;
readonly workflowStatus: Locator;
readonly activateWorkflowButton: Locator;
readonly deactivateWorkflowButton: Locator;
readonly addTriggerButton: Locator;
readonly commandMenu: Locator;
readonly workflowNameButton: Locator;
readonly triggerNode: Locator;
readonly background: Locator;

#actionNames: Record<WorkflowActionType, string> = {
'create-record': 'Create Record',
'update-record': 'Update Record',
'delete-record': 'Delete Record',
code: 'Code',
'send-email': 'Send Email',
};

#createdActionNames: Record<WorkflowActionType, string> = {
'create-record': 'Create Record',
'update-record': 'Update Record',
'delete-record': 'Delete Record',
code: 'Code - Serverless Function',
'send-email': 'Send Email',
};

#triggerNames: Record<WorkflowTriggerType, string> = {
'record-created': 'Record is Created',
'record-updated': 'Record is Updated',
'record-deleted': 'Record is Deleted',
manual: 'Launch manually',
};

#createdTriggerNames: Record<WorkflowTriggerType, string> = {
'record-created': 'Record is Created',
'record-updated': 'Record is Updated',
'record-deleted': 'Record is Deleted',
manual: 'Manual Trigger',
};

constructor({ page, workflowName }: { page: Page; workflowName: string }) {
this.#page = page;
this.workflowName = workflowName;

this.addStepButton = page.getByLabel('Add a step');
this.workflowStatus = page.getByTestId('workflow-visualizer-status');
this.activateWorkflowButton = page.getByLabel('Activate Workflow', {
exact: true,
});
this.deactivateWorkflowButton = page.getByLabel('Deactivate Workflow', {
exact: true,
});
this.addTriggerButton = page.getByText('Add a Trigger');
this.commandMenu = page.getByTestId('command-menu');
this.workflowNameButton = page.getByRole('button', {
name: this.workflowName,
});
this.triggerNode = this.#page.getByTestId('rf__node-trigger');
this.background = page.locator('.react-flow__pane');
}

async createOneWorkflow() {
const id = randomUUID();

const response = await createWorkflow({
page: this.#page,
workflowId: id,
workflowName: this.workflowName,
});

expect(response.status()).toBe(200);

const responseBody = await response.json();
expect(responseBody.data.createWorkflow.id).toBe(id);

this.workflowId = id;
}

async waitForWorkflowVisualizerLoad() {
await expect(this.workflowNameButton).toBeVisible();
}

async goToWorkflowVisualizerPage() {
await Promise.all([
this.#page.goto(`/object/workflow/${this.workflowId}`),

this.waitForWorkflowVisualizerLoad(),
]);
}

async createInitialTrigger(trigger: WorkflowTriggerType) {
await this.addTriggerButton.click();

const triggerName = this.#triggerNames[trigger];
const createdTriggerName = this.#createdTriggerNames[trigger];

const triggerOption = this.#page.getByText(triggerName);
await triggerOption.click();

await expect(this.triggerNode).toHaveClass(/selected/);
await expect(this.triggerNode).toContainText(createdTriggerName);
}

async createStep(action: WorkflowActionType) {
await this.addStepButton.click();

const actionName = this.#actionNames[action];
const createdActionName = this.#createdActionNames[action];

const actionToCreateOption = this.commandMenu.getByText(actionName);

const [createWorkflowStepResponse] = await Promise.all([
this.#page.waitForResponse((response) => {
if (!response.url().endsWith('/graphql')) {
return false;
}

const requestBody = response.request().postDataJSON();

return requestBody.operationName === 'CreateWorkflowVersionStep';
}),

actionToCreateOption.click(),
]);
const createWorkflowStepResponseBody =
await createWorkflowStepResponse.json();
const createdStepId =
createWorkflowStepResponseBody.data.createWorkflowVersionStep.id;

await expect(
this.#page.getByTestId('command-menu').getByRole('textbox').first(),
).toHaveValue(createdActionName);

const createdActionNode = this.#page
.locator('.react-flow__node.selected')
.getByText(createdActionName);

await expect(createdActionNode).toBeVisible();

const selectedNodes = this.#page.locator('.react-flow__node.selected');

await expect(selectedNodes).toHaveCount(1);

return {
createdStepId,
};
}

getStepNode(stepId: string) {
return this.#page.getByTestId(`rf__node-${stepId}`);
}

getDeleteNodeButton(nodeLocator: Locator) {
return nodeLocator.getByRole('button');
}

getAllStepNodes() {
return this.#page
.getByTestId(/^rf__node-.+$/)
.and(this.#page.getByTestId(/^((?!rf__node-trigger).)*$/))
.and(
this.#page.getByTestId(/^((?!rf__node-branch-\d+__create-step).)*$/),
);
}

async deleteStep(stepId: string) {
const stepNode = this.getStepNode(stepId);

await stepNode.click();

await Promise.all([
expect(stepNode).not.toBeVisible(),
this.#page.waitForResponse((response) => {
if (!response.url().endsWith('/graphql')) {
return false;
}

const requestBody = response.request().postDataJSON();

return (
requestBody.operationName === 'DeleteWorkflowVersionStep' &&
requestBody.variables.input.stepId === stepId
);
}),

this.getDeleteNodeButton(stepNode).click(),
]);
}

async deleteTrigger() {
await this.triggerNode.click();

await Promise.all([
expect(this.triggerNode).toContainText('Add a Trigger'),
this.#page.waitForResponse((response) => {
if (!response.url().endsWith('/graphql')) {
return false;
}

const requestBody = response.request().postDataJSON();

return (
requestBody.operationName === 'UpdateOneWorkflowVersion' &&
requestBody.variables.input.trigger === null
);
}),

this.getDeleteNodeButton(this.triggerNode).click(),
]);
}
}

export const test = base.extend<{ workflowVisualizer: WorkflowVisualizerPage }>(
{
workflowVisualizer: async ({ page }, use) => {
const workflowVisualizer = new WorkflowVisualizerPage({
page,
workflowName: 'Test Workflow',
});

await workflowVisualizer.createOneWorkflow();
await workflowVisualizer.goToWorkflowVisualizerPage();

await use(workflowVisualizer);

await deleteWorkflow({
page,
workflowId: workflowVisualizer.workflowId,
});
await destroyWorkflow({
page,
workflowId: workflowVisualizer.workflowId,
});
},
},
);
Loading

0 comments on commit 4dd1551

Please sign in to comment.