Skip to content

Commit

Permalink
[FR-344] feat: auto screenshot with Playwrite
Browse files Browse the repository at this point in the history
  • Loading branch information
agatha197 committed Jan 9, 2025
1 parent 16b95bf commit 9be3ac5
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 11 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,5 @@ yarn.lock
/playwright-report/
/blob-report/
/playwright/.cache/

e2e/screenshots/
3 changes: 3 additions & 0 deletions config.toml.sample
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,6 @@ webServerURL = "[Web server website URL. App will use the site instead of local
[pipeline]
#endpoint = "http://mlops.com:9500" # FastTrack API endpoint.
#frontendEndpoint = "http://mlops.com:9500" # FastTrack frontend endpoint.

[test]
# screenshotPath = "[Absolute path to save screenshots. If blank, it will be saved in the e2e/screenshots directory.]"
103 changes: 103 additions & 0 deletions e2e/screenshot.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { loginAsAdmin, getConfigValue, webuiEndpoint } from './test-util';
import { test } from '@playwright/test';
import * as path from 'path';

const routes = [
'/summary',
'/session',
'/session/start',
'/serving',
'/service',
'/service/start',
'/import',
'/data',
'/my-environment',
'/agent-summary',
'/statistics',
'/environment',
'/agent',
'/settings',
'/maintenance',
'/information',
'/usersettings',
'/credential',
'/logs',
'/error',
'/unauthorized',
];

test.describe('Screenshot all routes', () => {
let screenshotPath: string;
test.beforeEach(async ({ page, request }) => {
await loginAsAdmin(page);
const configValue = await getConfigValue(request, 'test.screenshotPath');
screenshotPath = configValue
? configValue
: path.resolve(__dirname + '/screenshots');
});

routes.forEach((route) => {
test(`screenshot ${route}`, async ({ page }) => {
await page.goto(`${webuiEndpoint}${route}`, {
waitUntil: 'networkidle',
});
await page.screenshot({
path: path.resolve(
`${screenshotPath}/${route.replace(/\//g, '_')}.png`,
),
fullPage: true,
});
});
test(`screenshot ${route} (dark mode)`, async ({ page }) => {
await page.goto(`${webuiEndpoint}${route}`, {
waitUntil: 'networkidle',
});
// Wait for the dark mode to be applied
await page.waitForTimeout(500);
await page.getByRole('button', { name: 'moon' }).click();
await page.screenshot({
path: path.resolve(
`${screenshotPath}/${route.replace(/\//g, '_')}_dark.png`,
),
fullPage: true,
});
});
test(`screenshot ${route} without sidebar`, async ({ page }) => {
await page.goto(`${webuiEndpoint}${route}`, {
waitUntil: 'networkidle',
});
await page.screenshot({
path: path.resolve(
`${screenshotPath}/${route.replace(/\//g, '_')}_no_sidebar.png`,
),
clip: {
x: 240,
y: 0,
width: (page.viewportSize()?.width || 0) - 240,
height: page.viewportSize()?.height || 0,
},
});
});
test(`screenshot ${route} without sidebar (dark mode)`, async ({
page,
}) => {
await page.goto(`${webuiEndpoint}${route}`, {
waitUntil: 'networkidle',
});
await page.getByRole('button', { name: 'moon' }).click();
// Wait for the dark mode to be applied
await page.waitForTimeout(500);
await page.screenshot({
path: path.resolve(
`${screenshotPath}/${route.replace(/\//g, '_')}_no_sidebar_dark.png`,
),
clip: {
x: 240,
y: 0,
width: (page.viewportSize()?.width || 0) - 240,
height: page.viewportSize()?.height || 0,
},
});
});
});
});
31 changes: 31 additions & 0 deletions e2e/test-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -290,3 +290,34 @@ export async function modifyConfigToml(
});
});
}

/**
* Get the value of a nested key from an object using dot notation
*
* @param obj
* @param key
* @returns
*/
function getNestedValue(obj: any, key: string) {
const keys = key.split('.');
let value = obj;
for (const k of keys) {
value = value?.[k];
}
return value;
}

/**
* Get the value of the key from the config.toml file
*
* @param request
* @param key
* @returns
*/
export async function getConfigValue(request: APIRequestContext, key: string) {
const configToml = await (
await request.get(`${webuiEndpoint}/config.toml`)
).text();
const config = TOML.parse(configToml);
return getNestedValue(config, key);
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@
"@babel/preset-typescript": "^7.24.7",
"@babel/types": "^7.25.2",
"@electron/packager": "^18.3.3",
"@playwright/test": "^1.46.1",
"@playwright/test": "^1.49.1",
"@rollup/plugin-commonjs": "^25.0.8",
"@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-replace": "^5.0.7",
Expand Down
47 changes: 37 additions & 10 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 9be3ac5

Please sign in to comment.