Skip to content

Commit

Permalink
[CI] Playwright testing improvements (#8985)
Browse files Browse the repository at this point in the history
* Run playwright tests in headless mode

* Add navigation helper

* Validate files

* test fix

* Remove 'headless'

* Fixes

* Fix for 'navigate' helper

* Further updates
  • Loading branch information
SchrodingersGat authored Feb 1, 2025
1 parent 66496fb commit 821b311
Show file tree
Hide file tree
Showing 16 changed files with 116 additions and 87 deletions.
19 changes: 19 additions & 0 deletions src/frontend/tests/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { baseUrl } from './defaults';

/**
* Open the filter drawer for the currently visible table
* @param page - The page object
Expand Down Expand Up @@ -62,3 +64,20 @@ export const setTableChoiceFilter = async (page, filter, value) => {
export const getRowFromCell = async (cell) => {
return cell.locator('xpath=ancestor::tr').first();
};

/**
* Navigate to the provided page, and wait for loading to complete
* @param page
* @param url
*/
export const navigate = async (page, url: string) => {
if (!url.startsWith(baseUrl)) {
if (url.startsWith('/')) {
url = url.slice(1);
}

url = `${baseUrl}/${url}`;
}

await page.goto(url, { waitUntil: 'domcontentloaded' });
};
7 changes: 4 additions & 3 deletions src/frontend/tests/login.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { expect } from './baseFixtures.js';
import { baseUrl, logoutUrl, user } from './defaults';
import { navigate } from './helpers.js';

/*
* Perform form based login operation from the "login" URL
Expand All @@ -8,7 +9,7 @@ export const doLogin = async (page, username?: string, password?: string) => {
username = username ?? user.username;
password = password ?? user.password;

await page.goto(logoutUrl);
await navigate(page, logoutUrl);
await expect(page).toHaveTitle(/^InvenTree.*$/);
await page.waitForURL('**/platform/login');
await page.getByLabel('username').fill(username);
Expand All @@ -31,7 +32,7 @@ export const doQuickLogin = async (
password = password ?? user.password;
url = url ?? baseUrl;

await page.goto(`${url}/login/?login=${username}&password=${password}`);
await navigate(page, `${url}/login/?login=${username}&password=${password}`);
await page.waitForURL('**/platform/home');

await page.getByLabel('navigation-menu').waitFor();
Expand All @@ -43,6 +44,6 @@ export const doQuickLogin = async (
};

export const doLogout = async (page) => {
await page.goto(`${baseUrl}/logout/`);
await navigate(page, 'logout');
await page.waitForURL('**/platform/login');
};
12 changes: 6 additions & 6 deletions src/frontend/tests/pages/pui_build.spec.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { test } from '../baseFixtures.ts';

Check failure on line 1 in src/frontend/tests/pages/pui_build.spec.ts

View workflow job for this annotation

GitHub Actions / Tests - Platform UI

[chromium] › pages/pui_build.spec.ts:10:1 › Build Order - Basic Tests

1) [chromium] › pages/pui_build.spec.ts:10:1 › Build Order - Basic Tests ───────────────────────── Test timeout of 90000ms exceeded.
import { baseUrl } from '../defaults.ts';
import {
clearTableFilters,
getRowFromCell,
navigate,
setTableChoiceFilter
} from '../helpers.ts';
import { doQuickLogin } from '../login.ts';

test('Build Order - Basic Tests', async ({ page }) => {
await doQuickLogin(page);

await page.goto(`${baseUrl}/part/`);
await navigate(page, 'part/');

// Navigate to the correct build order
await page.getByRole('tab', { name: 'Manufacturing', exact: true }).click();
Expand Down Expand Up @@ -90,7 +90,7 @@ test('Build Order - Basic Tests', async ({ page }) => {
test('Build Order - Edit', async ({ page }) => {
await doQuickLogin(page);

await page.goto(`${baseUrl}/manufacturing/build-order/22/`);
await navigate(page, 'manufacturing/build-order/22/');

// Check for expected text items
await page.getByText('Building for sales order').first().waitFor();
Expand All @@ -117,7 +117,7 @@ test('Build Order - Edit', async ({ page }) => {
test('Build Order - Build Outputs', async ({ page }) => {
await doQuickLogin(page);

await page.goto(`${baseUrl}/manufacturing/index/`);
await navigate(page, 'manufacturing/index/');
await page.getByRole('tab', { name: 'Build Orders', exact: true }).click();

// We have now loaded the "Build Order" table. Check for some expected texts
Expand Down Expand Up @@ -191,7 +191,7 @@ test('Build Order - Build Outputs', async ({ page }) => {
test('Build Order - Allocation', async ({ page }) => {
await doQuickLogin(page);

await page.goto(`${baseUrl}/manufacturing/build-order/1/line-items`);
await navigate(page, 'manufacturing/build-order/1/line-items');

// Expand the R_10K_0805 line item
await page.getByText('R_10K_0805_1%').first().click();
Expand Down Expand Up @@ -291,7 +291,7 @@ test('Build Order - Allocation', async ({ page }) => {
test('Build Order - Filters', async ({ page }) => {
await doQuickLogin(page);

await page.goto(`${baseUrl}/manufacturing/index/buildorders`);
await navigate(page, 'manufacturing/index/buildorders');

await clearTableFilters(page);
await page.getByText('1 - 24 / 24').waitFor();
Expand Down
39 changes: 19 additions & 20 deletions src/frontend/tests/pages/pui_part.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { test } from '../baseFixtures';

Check failure on line 1 in src/frontend/tests/pages/pui_part.spec.ts

View workflow job for this annotation

GitHub Actions / Tests - Platform UI

[chromium] › pages/pui_part.spec.ts:8:1 › Parts - Tabs

2) [chromium] › pages/pui_part.spec.ts:8:1 › Parts - Tabs ──────────────────────────────────────── Test timeout of 90000ms exceeded.
import { baseUrl } from '../defaults';
import { clearTableFilters, getRowFromCell } from '../helpers';
import { clearTableFilters, getRowFromCell, navigate } from '../helpers';
import { doQuickLogin } from '../login';

/**
Expand Down Expand Up @@ -45,7 +44,7 @@ test('Parts - Tabs', async ({ page }) => {
await page.getByRole('tab', { name: 'Used In' }).click();
await page.getByRole('tab', { name: 'Pricing' }).click();

await page.goto(`${baseUrl}/part/category/index/parts`);
await navigate(page, 'part/category/index/parts');
await page.getByText('Blue Chair').click();
await page.getByRole('tab', { name: 'Bill of Materials' }).click();
await page.getByRole('tab', { name: 'Build Orders' }).click();
Expand All @@ -54,7 +53,7 @@ test('Parts - Tabs', async ({ page }) => {
test('Parts - Manufacturer Parts', async ({ page }) => {
await doQuickLogin(page);

await page.goto(`${baseUrl}/part/84/suppliers`);
await navigate(page, 'part/84/suppliers');

await page.getByRole('tab', { name: 'Suppliers' }).click();
await page.getByText('Hammond Manufacturing').click();
Expand All @@ -67,7 +66,7 @@ test('Parts - Manufacturer Parts', async ({ page }) => {
test('Parts - Supplier Parts', async ({ page }) => {
await doQuickLogin(page);

await page.goto(`${baseUrl}/part/15/suppliers`);
await navigate(page, 'part/15/suppliers');

await page.getByRole('tab', { name: 'Suppliers' }).click();
await page.getByRole('cell', { name: 'DIG-84670-SJI' }).click();
Expand All @@ -81,14 +80,14 @@ test('Parts - Locking', async ({ page }) => {
await doQuickLogin(page);

// Navigate to a known assembly which is *not* locked
await page.goto(`${baseUrl}/part/104/bom`);
await navigate(page, 'part/104/bom');
await page.getByRole('tab', { name: 'Bill of Materials' }).click();
await page.getByLabel('action-button-add-bom-item').waitFor();
await page.getByRole('tab', { name: 'Parameters' }).click();
await page.getByLabel('action-button-add-parameter').waitFor();

// Navigate to a known assembly which *is* locked
await page.goto(`${baseUrl}/part/100/bom`);
await navigate(page, 'part/100/bom');
await page.getByRole('tab', { name: 'Bill of Materials' }).click();
await page.getByLabel('part-lock-icon').waitFor();
await page.getByText('Part is Locked', { exact: true }).waitFor();
Expand All @@ -107,15 +106,15 @@ test('Parts - Allocations', async ({ page }) => {
await doQuickLogin(page);

// Let's look at the allocations for a single stock item
await page.goto(`${baseUrl}/stock/item/324/`);
await navigate(page, 'stock/item/324/');
await page.getByRole('tab', { name: 'Allocations' }).click();

await page.getByRole('button', { name: 'Build Order Allocations' }).waitFor();
await page.getByRole('cell', { name: 'Making some blue chairs' }).waitFor();
await page.getByRole('cell', { name: 'Making tables for SO 0003' }).waitFor();

// Let's look at the allocations for an entire part
await page.goto(`${baseUrl}/part/74/details`);
await navigate(page, 'part/74/details');

// Check that the overall allocations are displayed correctly
await page.getByText('11 / 825').waitFor();
Expand Down Expand Up @@ -174,7 +173,7 @@ test('Parts - Pricing (Nothing, BOM)', async ({ page }) => {
await doQuickLogin(page);

// Part with no history
await page.goto(`${baseUrl}/part/82/pricing`);
await navigate(page, 'part/82/pricing');

await page.getByText('Small plastic enclosure, black').waitFor();
await page.getByRole('tab', { name: 'Part Pricing' }).click();
Expand All @@ -186,7 +185,7 @@ test('Parts - Pricing (Nothing, BOM)', async ({ page }) => {
await page.getByRole('button', { name: 'Supplier Pricing' }).isDisabled();

// Part with history
await page.goto(`${baseUrl}/part/108/pricing`);
await navigate(page, 'part/108/pricing');
await page.getByText('A chair - with blue paint').waitFor();
await page.getByRole('tab', { name: 'Part Pricing' }).click();
await page.getByLabel('Part Pricing').getByText('Part Pricing').waitFor();
Expand Down Expand Up @@ -224,7 +223,7 @@ test('Parts - Pricing (Supplier)', async ({ page }) => {
await doQuickLogin(page);

// Part
await page.goto(`${baseUrl}/part/55/pricing`);
await navigate(page, 'part/55/pricing');
await page.getByText('Ceramic capacitor, 100nF in').waitFor();
await page.getByRole('tab', { name: 'Part Pricing' }).click();
await page.getByLabel('Part Pricing').getByText('Part Pricing').waitFor();
Expand All @@ -250,7 +249,7 @@ test('Parts - Pricing (Variant)', async ({ page }) => {
await doQuickLogin(page);

// Part
await page.goto(`${baseUrl}/part/106/pricing`);
await navigate(page, 'part/106/pricing');
await page.getByText('A chair - available in multiple colors').waitFor();
await page.getByRole('tab', { name: 'Part Pricing' }).click();
await page.getByLabel('Part Pricing').getByText('Part Pricing').waitFor();
Expand All @@ -276,7 +275,7 @@ test('Parts - Pricing (Internal)', async ({ page }) => {
await doQuickLogin(page);

// Part
await page.goto(`${baseUrl}/part/65/pricing`);
await navigate(page, 'part/65/pricing');
await page.getByText('Socket head cap screw, M2').waitFor();
await page.getByRole('tab', { name: 'Part Pricing' }).click();
await page.getByLabel('Part Pricing').getByText('Part Pricing').waitFor();
Expand All @@ -301,7 +300,7 @@ test('Parts - Pricing (Purchase)', async ({ page }) => {
await doQuickLogin(page);

// Part
await page.goto(`${baseUrl}/part/69/pricing`);
await navigate(page, 'part/69/pricing');
await page.getByText('1.25mm Pitch, PicoBlade PCB').waitFor();
await page.getByRole('tab', { name: 'Part Pricing' }).click();
await page.getByLabel('Part Pricing').getByText('Part Pricing').waitFor();
Expand All @@ -322,7 +321,7 @@ test('Parts - Pricing (Purchase)', async ({ page }) => {
test('Parts - Attachments', async ({ page }) => {
await doQuickLogin(page);

await page.goto(`${baseUrl}/part/69/attachments`);
await navigate(page, 'part/69/attachments');

// Submit a new external link
await page.getByLabel('action-button-add-external-').click();
Expand All @@ -344,7 +343,7 @@ test('Parts - Attachments', async ({ page }) => {
test('Parts - Parameters', async ({ page }) => {
await doQuickLogin(page);

await page.goto(`${baseUrl}/part/69/parameters`);
await navigate(page, 'part/69/parameters');

// Create a new template
await page.getByLabel('action-button-add-parameter').click();
Expand All @@ -371,7 +370,7 @@ test('Parts - Parameters', async ({ page }) => {
test('Parts - Notes', async ({ page }) => {
await doQuickLogin(page);

await page.goto(`${baseUrl}/part/69/notes`);
await navigate(page, 'part/69/notes');

// Enable editing
await page.getByLabel('Enable Editing').waitFor();
Expand All @@ -393,7 +392,7 @@ test('Parts - Notes', async ({ page }) => {
test('Parts - 404', async ({ page }) => {
await doQuickLogin(page);

await page.goto(`${baseUrl}/part/99999/`);
await navigate(page, 'part/99999/');
await page.getByText('Page Not Found', { exact: true }).waitFor();

// Clear out any console error messages
Expand All @@ -403,7 +402,7 @@ test('Parts - 404', async ({ page }) => {
test('Parts - Revision', async ({ page }) => {
await doQuickLogin(page);

await page.goto(`${baseUrl}/part/906/details`);
await navigate(page, 'part/906/details');

await page.getByText('Revision of').waitFor();
await page.getByText('Select Part Revision').waitFor();
Expand Down
6 changes: 3 additions & 3 deletions src/frontend/tests/pages/pui_purchase_order.spec.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { test } from '../baseFixtures.ts';

Check failure on line 1 in src/frontend/tests/pages/pui_purchase_order.spec.ts

View workflow job for this annotation

GitHub Actions / Tests - Platform UI

[chromium] › pages/pui_purchase_order.spec.ts:173:1 › Purchase Orders - Order Parts

3) [chromium] › pages/pui_purchase_order.spec.ts:173:1 › Purchase Orders - Order Parts ─────────── Test timeout of 90000ms exceeded.
import { baseUrl } from '../defaults.ts';
import {
clearTableFilters,
clickButtonIfVisible,
navigate,
openFilterDrawer,
setTableChoiceFilter
} from '../helpers.ts';
Expand Down Expand Up @@ -39,7 +39,7 @@ test('Purchase Orders - List', async ({ page }) => {
test('Purchase Orders - Barcodes', async ({ page }) => {
await doQuickLogin(page);

await page.goto(`${baseUrl}/purchasing/purchase-order/13/detail`);
await navigate(page, 'purchasing/purchase-order/13/detail');
await page.getByRole('button', { name: 'Issue Order' }).waitFor();

// Display QR code
Expand Down Expand Up @@ -211,7 +211,7 @@ test('Purchase Orders - Order Parts', async ({ page }) => {
await page.getByRole('banner').getByRole('button').click();

// Order from the part detail page
await page.goto(`${baseUrl}/part/69/`);
await navigate(page, 'part/69/');
await page.waitForURL('**/part/69/**');

await page.getByLabel('action-menu-stock-actions').click();
Expand Down
18 changes: 12 additions & 6 deletions src/frontend/tests/pages/pui_sales_order.spec.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { test } from '../baseFixtures.ts';
import { baseUrl } from '../defaults.ts';
import { clearTableFilters, setTableChoiceFilter } from '../helpers.ts';
import {
clearTableFilters,
navigate,
setTableChoiceFilter
} from '../helpers.ts';
import { doQuickLogin } from '../login.ts';

test('Sales Orders - Tabs', async ({ page }) => {
await doQuickLogin(page);

await page.goto(`${baseUrl}/sales/index/`);
await navigate(page, 'sales/index/');
await page.waitForURL('**/platform/sales/**');

await page.getByRole('tab', { name: 'Sales Orders' }).click();
Expand All @@ -30,6 +33,9 @@ test('Sales Orders - Tabs', async ({ page }) => {

// Sales Order Details
await page.getByRole('tab', { name: 'Sales Orders' }).click();

await clearTableFilters(page);

await page.getByRole('cell', { name: 'SO0001' }).click();
await page
.getByLabel('Order Details')
Expand Down Expand Up @@ -57,7 +63,7 @@ test('Sales Orders - Tabs', async ({ page }) => {
test('Sales Orders - Basic Tests', async ({ page }) => {
await doQuickLogin(page);

await page.goto(`${baseUrl}/home`);
await navigate(page, 'home');
await page.getByRole('tab', { name: 'Sales' }).click();
await page.getByRole('tab', { name: 'Sales Orders' }).click();

Expand Down Expand Up @@ -100,12 +106,12 @@ test('Sales Orders - Basic Tests', async ({ page }) => {
test('Sales Orders - Shipments', async ({ page }) => {
await doQuickLogin(page);

await page.goto(`${baseUrl}/home`);
await navigate(page, 'home');
await page.getByRole('tab', { name: 'Sales' }).click();
await page.getByRole('tab', { name: 'Sales Orders' }).click();

await clearTableFilters(page);
// Click through to a particular sales order
await page.getByRole('tab', { name: 'Sales Orders' }).waitFor();
await page.getByRole('cell', { name: 'SO0006' }).first().click();
await page.getByRole('tab', { name: 'Shipments' }).click();

Expand Down
Loading

0 comments on commit 821b311

Please sign in to comment.