tests: organize playwright tests by feature suites and optimize CI runtime (#4687)

* starting realocating components FE

* tagging tests

* 📝 (.github/workflows/typescript_test.yml): remove unnecessary comment before the Playwright test execution step to improve readability and maintainability

* 📝 (.github/changes-filter.yaml): Update paths in changes-filter.yaml to categorize different sections of the project for testing purposes
🔧 (.github/workflows/typescript_test.yml): Refactor workflow to use paths-filter action for determining test suites based on changes in different project sections

* ✨ (changes-filter.yaml): reorganize and update paths for test categories, starter projects, components, workspace, api, and database
✨ (components): add new components for GradientWrapper, pageLayout, and paginatorComponent
🔧 (MainPage): update import path for PageLayout component
🔧 (SettingsPage): update import path for PageLayout component
🔧 (StorePage): update import path for PageLayout component

* ✨ (frontend): Update import paths for components to use common directory instead of core directory for better organization and consistency
🔧 (frontend): Remove duplicate import of PaginatorComponent in various files and import it from the common directory to reduce redundancy and improve maintainability

* 🔧 (changes-filter.yaml): remove unnecessary release section from changes-filter.yaml
🔧 (typescript_test.yml): refactor workflow to support input suites and release flag for test runs

* 📝 (changes-filter.yaml): remove unnecessary entries from components section and add missing entries to workspace section for better organization and filtering of changes
🔧 (changes-filter.yaml): update changes-filter.yaml to include missing utils files in the frontend/src/utils directory
🔧 (typescript_test.yml): remove redundant code block that sets SUITES variable to default values as it is no longer needed due to changes in the changes-filter.yaml file

* ✨ (actionsMainPage-shard-1.spec.ts): Update test tags to remove unnecessary tags for better organization and clarity
📝 (store-shard-2.spec.ts): Update test tags to remove unnecessary tags for better organization and clarity
📝 (generalBugs-shard-4.spec.ts): Update test tags to remove unnecessary tags for better organization and clarity
📝 (generalBugs-shard-9.spec.ts): Update test tags to remove unnecessary tags for better organization and clarity
📝 (deleteComponents.spec.ts): Update test tags to remove unnecessary tags for better organization and clarity
📝 (deleteFlows.spec.ts): Update test tags to remove unnecessary tags for better organization and clarity

✨ (dragAndDrop.spec.ts): Refactor drag and drop test to improve readability and maintainability
✨ (flowPage.spec.ts): Refactor save test in Flow Page to improve readability and maintainability
✨ (store-shard-0.spec.ts): Refactor Store test to improve readability and maintainability
✨ (store-shard-1.spec.ts): Refactor Store test to improve readability and maintainability

✨ (store-shard-3.spec.ts): Remove unnecessary tags from test descriptions to improve clarity and consistency
✨ (userSettings.spec.ts): Remove unnecessary tags from test descriptions to improve clarity and consistency
✨ (general-bugs-shard-3909.spec.ts): Remove unnecessary tags from test descriptions to improve clarity and consistency

📝 (frontend): Update test tags in regression tests to remove unnecessary tags for better organization and clarity
📝 (frontend): Update test file paths in tsconfig.json to match the new file structure for consistency and maintainability

* [autofix.ci] apply automated fixes

* [autofix.ci] apply automated fixes

* Update paths-filter action to v3 and adjust filter configuration file

* Add logging to matrix setup in TypeScript test workflow

* Refactor decisionFlow.spec.ts to improve test setup and execution flow

* Refactor import paths for genericIconComponent and shadTooltipComponent in PlaygroundButton component

* feat: add release input to CI workflows for enhanced deployment control

* Fix: Correct 'release' input type in CI workflow configuration

* [autofix.ci] apply automated fixes

* Refactor Blog Writer test: streamline setup and interaction steps

* Refactor test cases to improve modal handling and streamline API key input logic

* Add test grep pattern to GitHub Actions workflow for targeted test execution

- Introduced `test_grep` output in the `determine-test-suite` job to generate a grep pattern based on changed files or input suites.
- Updated Playwright test execution to use the generated grep pattern, allowing for more targeted test runs.
- Enhanced the `Set Matrix` step to include tag processing for test filtering.

* Enhance tag filtering in test workflow with regex lookaheads

* Fix syntax for default suite input in GitHub Actions workflow

* Update GitHub Actions to handle empty suite input for release builds

* Escape regex lookaheads and quotes for GitHub Actions in test workflow

* Update regex pattern and quote escaping in TypeScript test workflow

* Use single quotes for echo command in GitHub Actions script

* Refactor tag handling in GitHub Actions to use OR logic for grep patterns

* 🔧 (FlowPage/index.tsx): Remove unnecessary empty line to improve code readability and consistency

* 📝 (FlowPage/index.tsx): add missing line break for better code readability

* Refactor import path and reorder CSS classes for consistency in UpdateAllComponents component

* [autofix.ci] apply automated fixes

* Update import path for PaginatorComponent in AdminPage index.tsx

* ✨ (logs.spec.ts): introduce a new variable 'modalCount' to keep track of the number of modals opened in the test suite

* 📝 (filterSidebar.spec.ts): remove unnecessary test steps related to filter removal and sidebar interactions to simplify and improve test focus on main functionality

* ✅ (logs.spec.ts): add tests to ensure proper interaction with logs feature in the frontend application

* ✅ (similarity.spec.ts): add a test tag for release and components to categorize the test case
💡 (similarity.spec.ts): add a comment to explain the purpose of the test case and the condition for skipping the test

* ✅ (decisionFlow.spec.ts): add missing newline before async function declaration to improve code readability

* ✅ (textInputOutput.spec.ts): skip the test for TextInputOutputComponent to exclude it from the test suite temporarily

---------

Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
Cristhian Zanforlin Lousa 2024-11-25 17:55:03 -03:00 • committed by GitHub
commit 989cefd0ac
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
331 changed files with 10386 additions and 9694 deletions

View file

@ -2,56 +2,59 @@ import { expect, test } from "@playwright/test";
import uaParser from "ua-parser-js";
// TODO: This component doesn't have table input needs updating
test("user must be able to interact with table input component", async ({
page,
}) => {
await page.goto("/");
await page.waitForSelector('[data-testid="mainpage_title"]', {
timeout: 30000,
});
test(
"user must be able to interact with table input component",
{
tag: ["@release", "@workspace"],
},
async ({ page }) => {
await page.goto("/");
await page.waitForSelector('[data-testid="mainpage_title"]', {
timeout: 30000,
});
await page.waitForSelector('[id="new-project-btn"]', {
timeout: 30000,
});
await page.waitForSelector('[id="new-project-btn"]', {
timeout: 30000,
});
let modalCount = 0;
try {
const modalTitleElement = await page?.getByTestId("modal-title");
if (modalTitleElement) {
modalCount = await modalTitleElement.count();
let modalCount = 0;
try {
const modalTitleElement = await page?.getByTestId("modal-title");
if (modalTitleElement) {
modalCount = await modalTitleElement.count();
}
} catch (error) {
modalCount = 0;
}
} catch (error) {
modalCount = 0;
}
const randomText = Math.random().toString(36).substring(7);
const secondRandomText = Math.random().toString(36).substring(7);
const thirdRandomText = Math.random().toString(36).substring(7);
const randomText = Math.random().toString(36).substring(7);
const secondRandomText = Math.random().toString(36).substring(7);
const thirdRandomText = Math.random().toString(36).substring(7);
const getUA = await page.evaluate(() => navigator.userAgent);
const userAgentInfo = uaParser(getUA);
const getUA = await page.evaluate(() => navigator.userAgent);
const userAgentInfo = uaParser(getUA);
while (modalCount === 0) {
await page.getByText("New Flow", { exact: true }).click();
await page.waitForTimeout(3000);
modalCount = await page.getByTestId("modal-title")?.count();
}
await page.waitForSelector('[data-testid="blank-flow"]', {
timeout: 30000,
});
await page.getByTestId("blank-flow").click();
while (modalCount === 0) {
await page.getByText("New Flow", { exact: true }).click();
await page.waitForTimeout(3000);
modalCount = await page.getByTestId("modal-title")?.count();
}
await page.waitForSelector('[data-testid="blank-flow"]', {
timeout: 30000,
});
await page.getByTestId("blank-flow").click();
await page.waitForTimeout(1000);
await page.waitForTimeout(1000);
await page.getByTestId("sidebar-custom-component-button").click();
await page.getByTestId("sidebar-custom-component-button").click();
await page.getByTestId("zoom_out").click();
await page.getByTestId("zoom_out").click();
await page.getByTestId("zoom_out").click();
await page.getByTestId("zoom_out").click();
await page.getByTestId("div-generic-node").click();
await page.getByTestId("code-button-modal").click();
await page.getByTestId("div-generic-node").click();
await page.getByTestId("code-button-modal").click();
const customCodeWithError = `
const customCodeWithError = `
# from langflow.field_typing import Data
from langflow.custom import Component
from langflow.io import TableInput, Output
@ -96,94 +99,95 @@ class CustomComponent(Component):
return data
`;
await page.locator("textarea").press(`ControlOrMeta+a`);
await page.locator("textarea").fill(customCodeWithError);
await page.locator("textarea").press(`ControlOrMeta+a`);
await page.locator("textarea").fill(customCodeWithError);
await page.getByText("Check & Save").last().click();
await page.getByText("Check & Save").last().click();
await page.waitForTimeout(1000);
await page.waitForTimeout(1000);
await page.getByText("Open Table").click();
await page.getByText("Open Table").click();
await page.waitForTimeout(1000);
await page.waitForTimeout(1000);
const visibleTextsGroup1 = ["Alpha", "Bravo", "Charlie", "Delta", "Echo"];
const visibleTextsGroup2 = ["X1", "Y2", "Z3", "W4", "V5"];
const visibleTextsGroup3 = ["P1", "Q2", "R3", "S4", "T5"];
const visibleTextsGroup4 = ["F1", "G2", "H3", "I4", "J5"];
const visibleTextsGroup1 = ["Alpha", "Bravo", "Charlie", "Delta", "Echo"];
const visibleTextsGroup2 = ["X1", "Y2", "Z3", "W4", "V5"];
const visibleTextsGroup3 = ["P1", "Q2", "R3", "S4", "T5"];
const visibleTextsGroup4 = ["F1", "G2", "H3", "I4", "J5"];
const allVisibleTexts = [
...visibleTextsGroup1,
...visibleTextsGroup2,
...visibleTextsGroup3,
...visibleTextsGroup4,
];
const allVisibleTexts = [
...visibleTextsGroup1,
...visibleTextsGroup2,
...visibleTextsGroup3,
...visibleTextsGroup4,
];
for (const text of allVisibleTexts) {
await expect(page.getByText(text).last()).toBeVisible();
}
for (const text of allVisibleTexts) {
await expect(page.getByText(text).last()).toBeVisible();
}
await page.locator(".ag-cell-value").first().click();
await page.locator(".ag-cell-value").first().click();
await page.getByPlaceholder("Empty").fill(randomText);
await page.getByText("Save").last().click();
await page.waitForTimeout(500);
await page.getByPlaceholder("Empty").fill(randomText);
await page.getByText("Save").last().click();
await page.waitForTimeout(500);
await page.locator(".ag-cell-value").nth(12).click();
await page.locator(".ag-cell-value").nth(12).click();
await page.getByPlaceholder("Empty").fill(secondRandomText);
await page.getByText("Save").last().click();
await page.waitForTimeout(500);
await page.getByPlaceholder("Empty").fill(secondRandomText);
await page.getByText("Save").last().click();
await page.waitForTimeout(500);
await page.locator(".ag-cell-value").nth(24).click();
await page.waitForTimeout(500);
await page.locator(".ag-cell-value").nth(24).click();
await page.waitForTimeout(500);
await page.getByPlaceholder("Empty").fill(thirdRandomText);
await page.getByText("Save").last().click();
await page.getByPlaceholder("Empty").fill(thirdRandomText);
await page.getByText("Save").last().click();
await page.waitForTimeout(500);
await page.waitForTimeout(500);
expect(page.getByText(randomText)).toBeVisible();
expect(page.getByText(secondRandomText)).toBeVisible();
expect(page.getByText(thirdRandomText)).toBeVisible();
expect(page.getByText(randomText)).toBeVisible();
expect(page.getByText(secondRandomText)).toBeVisible();
expect(page.getByText(thirdRandomText)).toBeVisible();
await page.locator('input[type="checkbox"]').last().click();
await page.locator('input[type="checkbox"]').last().click();
await page.getByTestId("icon-Copy").last().click();
await page.getByTestId("icon-Copy").last().click();
await page.waitForTimeout(500);
await page.waitForTimeout(500);
let numberOfCopiedRows = await page.getByText(thirdRandomText).count();
expect(numberOfCopiedRows).toBe(2);
let numberOfCopiedRows = await page.getByText(thirdRandomText).count();
expect(numberOfCopiedRows).toBe(2);
await page.locator('input[type="checkbox"]').last().click();
await page.getByTestId("icon-Trash2").last().click();
await page.locator('input[type="checkbox"]').last().click();
await page.getByTestId("icon-Trash2").last().click();
await page.waitForTimeout(500);
await page.waitForTimeout(500);
await page.locator('input[type="checkbox"]').last().click();
await page.getByTestId("icon-Trash2").click();
await page.locator('input[type="checkbox"]').last().click();
await page.getByTestId("icon-Trash2").click();
numberOfCopiedRows = await page.getByText(thirdRandomText).count();
expect(numberOfCopiedRows).toBe(0);
numberOfCopiedRows = await page.getByText(thirdRandomText).count();
expect(numberOfCopiedRows).toBe(0);
await page.getByText("Close").last().click();
await page.getByText("Close").last().click();
await page.waitForTimeout(500);
await page.waitForTimeout(500);
await page.getByText("Open Table").click();
await page.getByText("Open Table").click();
await page.waitForTimeout(1000);
await page.waitForTimeout(1000);
const visibleTexts = ["Alpha", "Bravo", "Charlie", "Delta", "Echo"];
const notVisibleTexts = ["X1", "thirdRandomText"];
const visibleTexts = ["Alpha", "Bravo", "Charlie", "Delta", "Echo"];
const notVisibleTexts = ["X1", "thirdRandomText"];
await Promise.all(
visibleTexts.map((text) => expect(page.getByText(text)).toBeVisible()),
);
await Promise.all(
notVisibleTexts.map((text) =>
expect(page.getByText(text)).not.toBeVisible(),
),
);
});
await Promise.all(
visibleTexts.map((text) => expect(page.getByText(text)).toBeVisible()),
);
await Promise.all(
notVisibleTexts.map((text) =>
expect(page.getByText(text)).not.toBeVisible(),
),
);
},
);