Skip to content

Commit

Permalink
Add teamview screenshots generator based on playwright tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Kostya Bats authored and kbats183 committed Sep 15, 2024
1 parent 62b7f79 commit 043e365
Show file tree
Hide file tree
Showing 9 changed files with 281 additions and 68 deletions.
7 changes: 7 additions & 0 deletions src/frontend/content-gen/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
node_modules/
test-results/
tests/contestInfo.json
tests/screenshots/
playwright-report/
blob-report/
playwright/.cache/
74 changes: 74 additions & 0 deletions src/frontend/content-gen/package-lock.json

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

19 changes: 19 additions & 0 deletions src/frontend/content-gen/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "content-gen",
"version": "1.0.0",
"description": "",
"main": "index.js",
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@playwright/test": "^1.32.3",
"@types/node": "^22.5.4",
"fs": "0.0.1-security",
"path": "^0.12.7"
},
"scripts": {
"install-browsers": "playwright install --with-deps",
"teamview": "playwright test teamview.spec.ts"
}
}
45 changes: 45 additions & 0 deletions src/frontend/content-gen/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { defineConfig, devices } from '@playwright/test';

/**
* Read environment variables from file.
* https://github.com/motdotla/dotenv
*/
// import dotenv from 'dotenv';
// dotenv.config({ path: path.resolve(__dirname, '.env') });

/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: './tests',
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: 0,
/* Opt out of parallel tests on CI. */
// workers: process.env.CI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: [ ["html", { open: "never" }] ],
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
// baseURL: 'http://127.0.0.1:3000',

/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry',
},

/* Configure projects for major browsers */
projects: [
{
name: "chromium",
use: {
...devices["Desktop Chrome"],
channel: "chrome",
viewport: { width: 1920, height: 1080 },
}
}
]
});
61 changes: 61 additions & 0 deletions src/frontend/content-gen/tests/teamview.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import test, { PlaywrightTestArgs, TestInfo, expect, request } from "@playwright/test";
import { TeamMediaType, TeamId, ExternalTeamViewSettings, Widget, ContestInfo } from "../../generated/api"
import * as fs from "node:fs";
import * as path from "node:path";

const BACKEND_URL = process.env.BACKEND_URL ?? "http://localhost:8080";

const getTeamViewSettings = async (teamId: TeamId, media: TeamMediaType) => {
const adminApiContext = await request.newContext({ baseURL: `${BACKEND_URL}/api/admin/` });
const adminSettings: ExternalTeamViewSettings = {"mediaTypes": [media],"teamId": teamId,"showTaskStatus": false,"showAchievement": false,"showTimeLine": false};
const resp = await adminApiContext.post("./teamView/preview", {
data: adminSettings,
headers: { "Content-Type": "application/json" }
});
expect.soft(resp.ok()).toBeTruthy();
const widget = (await resp.json()) as Widget;
widget.type = Widget.Type.TeamViewWidget;
widget.location = { sizeX: 1920, sizeY: 1080, positionX: 0, positionY: 0 };
return widget;
}

const testTeamViewOneMedia = (teamId: TeamId, media: TeamMediaType) =>
async ({ page }: PlaywrightTestArgs, testInfo: TestInfo) => {
const widgets = [await getTeamViewSettings(teamId, media)];
await page.goto(`${BACKEND_URL}/overlay?forceWidgets=${encodeURIComponent(JSON.stringify(widgets))}`);

while (true) {
await page.waitForTimeout(500);
const teamViewDisplay = await page.locator(".TeamViewContainer").first().evaluate((el) => {
return window.getComputedStyle(el).getPropertyValue("display");
});
if (teamViewDisplay !== "none") {
break;
}
}
await page.waitForTimeout(1000);

const testName = `${teamId}_${media}`;
const screenshot = await page.screenshot({ path: `tests/screenshots/${testName}.png` });

await testInfo.attach("page", {
body: screenshot,
contentType: "image/png",
});
};


const contestInfo = JSON.parse(fs.readFileSync(path.join(__dirname, "contestInfo.json")).toString("utf-8")) as ContestInfo;

test.describe("TeamViews", async () => {
// const contestInfo = (await contestInfoRequest.json()) as ContestInfo;
const medias = [TeamMediaType.camera, TeamMediaType.screen];
for (let media of medias) {
for (let team of contestInfo.teams) {
if (team.isHidden) {
continue;
}
test(`${team.id}_${media}`, testTeamViewOneMedia(team.id, media));
}
}
});
1 change: 1 addition & 0 deletions src/frontend/overlay/src/components/layouts/MainLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ const WIDGETS = {
const useWidgets = () => {
const queryParams = useQueryParams();
if(queryParams.has("forceWidgets")) {
console.info("forceWidgets=", queryParams.get("forceWidgets"));
return JSON.parse(queryParams.get("forceWidgets")) as Record<Widget["widgetId"], Widget>;
} else {
return useAppSelector(state => state.widgets.widgets);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ const RoundedTeamMediaHolder = styled(TeamMediaHolder)`
border-radius: ${c.GLOBAL_BORDER_RADIUS};
`;

const TeamViewContainer = styled.div<{ show: boolean; animation?: Keyframes; animationStyle: string }>`
const TeamViewContainer = styled.div.attrs({
className: "TeamViewContainer",
})<{ show: boolean; animation?: Keyframes; animationStyle: string }>`
width: 100%;
height: 100%;
display: ${props => props.show ? "flex" : "none"};
Expand Down
Loading

0 comments on commit 043e365

Please sign in to comment.