mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-07 16:33:51 +00:00
V2 e2e playwright (#343)
* test: create utility for uploading test-db * chore: upgrade deps * refactor: remove unused functions * chore: create testing boilerplate * test: upload showfile
This commit is contained in:
@@ -20,6 +20,28 @@ From the project root, run the following commands
|
||||
- __Install the project dependencies__ by running `pnpm i`
|
||||
- __Run dev mode__ by running `turbo dev`
|
||||
|
||||
## TESTING
|
||||
|
||||
Generally we have 2 types of tests.
|
||||
- Unit tests for functions that contain business logic
|
||||
- End-to-end tests for core features
|
||||
|
||||
### Unit tests
|
||||
Unit tests are contained in mostly all the apps and packages (client, server and utils)
|
||||
|
||||
You can run unit tests by running turbo `turbo test:pipeline` from the project root.
|
||||
This will run all tests and close test runner.
|
||||
|
||||
Alternatively you can navigate to an app or project and run `pnpm test` to run those tests in watch mode
|
||||
|
||||
### E2E tests
|
||||
E2E tests are in a separate package. On running, [playwright](https://playwright.dev/) will spin up an instance of the webserver to test against
|
||||
These tests also run against a separate version of the DB (test-db)
|
||||
|
||||
You can run playwright tests from project root with `pnpm e2e`
|
||||
|
||||
When writing tests, it can be handy to run playwright in interactive mode with `pnpm e2e:i`. You would need to manually start the webserver with `pnpm dev:server`
|
||||
|
||||
## CREATE AN INSTALLABLE FILE (Windows | MacOS | Linux)
|
||||
|
||||
Ontime uses Electron to distribute the application.
|
||||
|
||||
@@ -213,13 +213,13 @@ export const shutdown = async (exitCode = 0) => {
|
||||
|
||||
process.on('exit', (code) => console.log(`Ontime exited with code: ${code}`));
|
||||
|
||||
process.on('unhandledRejection', async () => {
|
||||
logger.error('SERVER', 'Error: unhandled rejection');
|
||||
process.on('unhandledRejection', async (error) => {
|
||||
logger.error('SERVER', `Error: unhandled rejection ${error}`);
|
||||
await shutdown(1);
|
||||
});
|
||||
|
||||
process.on('uncaughtException', async () => {
|
||||
logger.error('SERVER', 'Error: uncaught exception');
|
||||
process.on('uncaughtException', async (error) => {
|
||||
logger.error('SERVER', `Error: uncaught exception ${error}`);
|
||||
await shutdown(1);
|
||||
});
|
||||
|
||||
|
||||
@@ -288,13 +288,3 @@ export const dbUpload = async (req, res) => {
|
||||
const file = req.file.path;
|
||||
await uploadAndParse(file, req, res, options);
|
||||
};
|
||||
|
||||
// Create controller for POST request to '/ontime/dbpath'
|
||||
// Returns -
|
||||
export const dbPathToUpload = async (req, res) => {
|
||||
if (!req.body.path) {
|
||||
res.status(400).send({ message: 'Path to file not found' });
|
||||
return;
|
||||
}
|
||||
await uploadAndParse(req.body.path, req, res);
|
||||
};
|
||||
|
||||
@@ -2,7 +2,6 @@ import express from 'express';
|
||||
import { uploadFile } from '../utils/upload.js';
|
||||
import {
|
||||
dbDownload,
|
||||
dbPathToUpload,
|
||||
dbUpload,
|
||||
getAliases,
|
||||
getInfo,
|
||||
@@ -19,11 +18,11 @@ import {
|
||||
} from '../controllers/ontimeController.js';
|
||||
|
||||
import {
|
||||
viewValidator,
|
||||
validateAliases,
|
||||
validateUserFields,
|
||||
validateSettings,
|
||||
validateOSC,
|
||||
validateSettings,
|
||||
validateUserFields,
|
||||
viewValidator,
|
||||
} from '../controllers/ontimeController.validate.js';
|
||||
|
||||
export const router = express.Router();
|
||||
@@ -69,6 +68,3 @@ router.get('/osc', getOSC);
|
||||
|
||||
// create route between controller and '/ontime/osc' endpoint
|
||||
router.post('/osc', validateOSC, postOSC);
|
||||
|
||||
// create route between controller and '/ontime/dbpath' endpoint
|
||||
router.post('/dbpath', dbPathToUpload);
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"rundown": [],
|
||||
"eventData": {
|
||||
"title": "All about Carlos demo event",
|
||||
"publicUrl": "www.getontime.no",
|
||||
"publicInfo": "WiFi: demoproject \nPassword: ontimeproject",
|
||||
"backstageUrl": "www.getontime.no",
|
||||
"backstageInfo": "WiFi: demobackstage\nPassword: ontimeproject",
|
||||
"endMessage": ""
|
||||
},
|
||||
"settings": {
|
||||
"app": "ontime",
|
||||
"version": 2,
|
||||
"serverPort": 4001,
|
||||
"lock": null,
|
||||
"pinCode": "1234",
|
||||
"timeFormat": "24"
|
||||
},
|
||||
"viewSettings": {
|
||||
"overrideStyles": false
|
||||
},
|
||||
"aliases": [
|
||||
{
|
||||
"id": "0b0b3",
|
||||
"enabled": true,
|
||||
"alias": "test",
|
||||
"pathAndParams": "lower?bg=ff2&text=f00&size=0.6&transition=5"
|
||||
}
|
||||
],
|
||||
"userFields": {
|
||||
"user0": "user0",
|
||||
"user1": "user1",
|
||||
"user2": "user2",
|
||||
"user3": "user3",
|
||||
"user4": "user4",
|
||||
"user5": "user5",
|
||||
"user6": "user6",
|
||||
"user7": "user7",
|
||||
"user8": "user8",
|
||||
"user9": "user9"
|
||||
},
|
||||
"osc": {
|
||||
"portIn": 8888,
|
||||
"portOut": 9999,
|
||||
"targetIP": "127.0.0.1",
|
||||
"enabledIn": false,
|
||||
"enabledOut": false,
|
||||
"subscriptions": {
|
||||
"onLoad": [],
|
||||
"onStart": [],
|
||||
"onPause": [],
|
||||
"onStop": [],
|
||||
"onUpdate": [],
|
||||
"onFinish": []
|
||||
}
|
||||
},
|
||||
"http": {
|
||||
"http": {
|
||||
"user": null,
|
||||
"pwd": null,
|
||||
"messages": {
|
||||
"onLoad": {
|
||||
"url": "",
|
||||
"enabled": false
|
||||
},
|
||||
"onStart": {
|
||||
"url": "",
|
||||
"enabled": false
|
||||
},
|
||||
"onUpdate": {
|
||||
"url": "",
|
||||
"enabled": false
|
||||
},
|
||||
"onPause": {
|
||||
"url": "",
|
||||
"enabled": false
|
||||
},
|
||||
"onStop": {
|
||||
"url": "",
|
||||
"enabled": false
|
||||
},
|
||||
"onFinish": {
|
||||
"url": "",
|
||||
"enabled": false
|
||||
}
|
||||
},
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { test } from '@playwright/test';
|
||||
|
||||
test('test', async ({ page }) => {
|
||||
await page.goto('http://localhost:4001/editor');
|
||||
await page.getByRole('button', { name: 'Event...' }).click();
|
||||
await page.getByRole('menuitem', { name: 'Delete all events' }).click();
|
||||
|
||||
await page.getByRole('button', { name: 'Upload showfile' }).click();
|
||||
await page.getByLabel('Select file to upload').click();
|
||||
await page.getByLabel('Select file to upload').setInputFiles('e2e/tests/fixtures/test-db.json');
|
||||
await page.getByRole('button', { name: 'Upload' }).click();
|
||||
await page.getByRole('button', { name: 'Close' }).click();
|
||||
|
||||
// asset test events
|
||||
await page.getByPlaceholder('Start').first().click();
|
||||
await page.getByText('First test event').click();
|
||||
await page.getByTestId('delay-input').click();
|
||||
await page
|
||||
.locator('div')
|
||||
.filter({ hasText: /^SED\+10minNew start: 10:10:00$/ })
|
||||
.getByPlaceholder('Start')
|
||||
.click();
|
||||
await page.getByText('+10minNew start: 10:10:00').click();
|
||||
await page.getByText('Second test event').click();
|
||||
await page.getByText('Lunch').click();
|
||||
await page.getByText('Third test event').click();
|
||||
});
|
||||
Vendored
+183
@@ -0,0 +1,183 @@
|
||||
{
|
||||
"rundown": [
|
||||
{
|
||||
"title": "First test event",
|
||||
"subtitle": "",
|
||||
"presenter": "",
|
||||
"note": "",
|
||||
"endAction": "continue",
|
||||
"timerType": "count-down",
|
||||
"timeStart": 32400000,
|
||||
"timeEnd": 36000000,
|
||||
"duration": 3600000,
|
||||
"isPublic": true,
|
||||
"skip": false,
|
||||
"colour": "",
|
||||
"user0": "",
|
||||
"user1": "",
|
||||
"user2": "",
|
||||
"user3": "",
|
||||
"user4": "",
|
||||
"user5": "",
|
||||
"user6": "",
|
||||
"user7": "",
|
||||
"user8": "",
|
||||
"user9": "",
|
||||
"type": "event",
|
||||
"revision": 4,
|
||||
"id": "aa42f"
|
||||
},
|
||||
{
|
||||
"duration": 600000,
|
||||
"type": "delay",
|
||||
"revision": 0,
|
||||
"id": "b1d5a"
|
||||
},
|
||||
{
|
||||
"title": "Second test event",
|
||||
"subtitle": "",
|
||||
"presenter": "",
|
||||
"note": "",
|
||||
"endAction": "continue",
|
||||
"timerType": "count-down",
|
||||
"timeStart": 36000000,
|
||||
"timeEnd": 39600000,
|
||||
"duration": 3600000,
|
||||
"isPublic": true,
|
||||
"skip": false,
|
||||
"colour": "",
|
||||
"user0": "",
|
||||
"user1": "",
|
||||
"user2": "",
|
||||
"user3": "",
|
||||
"user4": "",
|
||||
"user5": "",
|
||||
"user6": "",
|
||||
"user7": "",
|
||||
"user8": "",
|
||||
"user9": "",
|
||||
"type": "event",
|
||||
"revision": 2,
|
||||
"id": "d71bc"
|
||||
},
|
||||
{
|
||||
"title": "Lunch",
|
||||
"type": "block",
|
||||
"id": "91682"
|
||||
},
|
||||
{
|
||||
"title": "Third test event",
|
||||
"subtitle": "",
|
||||
"presenter": "",
|
||||
"note": "",
|
||||
"endAction": "continue",
|
||||
"timerType": "count-down",
|
||||
"timeStart": 39600000,
|
||||
"timeEnd": 720000,
|
||||
"duration": 47520000,
|
||||
"isPublic": true,
|
||||
"skip": false,
|
||||
"colour": "",
|
||||
"user0": "",
|
||||
"user1": "",
|
||||
"user2": "",
|
||||
"user3": "",
|
||||
"user4": "",
|
||||
"user5": "",
|
||||
"user6": "",
|
||||
"user7": "",
|
||||
"user8": "",
|
||||
"user9": "",
|
||||
"type": "event",
|
||||
"revision": 2,
|
||||
"id": "da5b4"
|
||||
}
|
||||
],
|
||||
"eventData": {
|
||||
"title": "All about Carlos demo event",
|
||||
"publicUrl": "www.getontime.no",
|
||||
"publicInfo": "WiFi: demoproject \nPassword: ontimeproject",
|
||||
"backstageUrl": "www.getontime.no",
|
||||
"backstageInfo": "WiFi: demobackstage\nPassword: ontimeproject",
|
||||
"endMessage": ""
|
||||
},
|
||||
"settings": {
|
||||
"app": "ontime",
|
||||
"version": 2,
|
||||
"serverPort": 4001,
|
||||
"lock": null,
|
||||
"pinCode": "1234",
|
||||
"timeFormat": "24"
|
||||
},
|
||||
"viewSettings": {
|
||||
"overrideStyles": false
|
||||
},
|
||||
"aliases": [
|
||||
{
|
||||
"id": "0b0b3",
|
||||
"enabled": true,
|
||||
"alias": "test",
|
||||
"pathAndParams": "lower?bg=ff2&text=f00&size=0.6&transition=5"
|
||||
}
|
||||
],
|
||||
"userFields": {
|
||||
"user0": "user0",
|
||||
"user1": "user1",
|
||||
"user2": "user2",
|
||||
"user3": "user3",
|
||||
"user4": "user4",
|
||||
"user5": "user5",
|
||||
"user6": "user6",
|
||||
"user7": "user7",
|
||||
"user8": "user8",
|
||||
"user9": "user9"
|
||||
},
|
||||
"osc": {
|
||||
"portIn": 8888,
|
||||
"portOut": 9999,
|
||||
"targetIP": "127.0.0.1",
|
||||
"enabledIn": false,
|
||||
"enabledOut": false,
|
||||
"subscriptions": {
|
||||
"onLoad": [],
|
||||
"onStart": [],
|
||||
"onPause": [],
|
||||
"onStop": [],
|
||||
"onUpdate": [],
|
||||
"onFinish": []
|
||||
}
|
||||
},
|
||||
"http": {
|
||||
"http": {
|
||||
"user": null,
|
||||
"pwd": null,
|
||||
"messages": {
|
||||
"onLoad": {
|
||||
"url": "",
|
||||
"enabled": false
|
||||
},
|
||||
"onStart": {
|
||||
"url": "",
|
||||
"enabled": false
|
||||
},
|
||||
"onUpdate": {
|
||||
"url": "",
|
||||
"enabled": false
|
||||
},
|
||||
"onPause": {
|
||||
"url": "",
|
||||
"enabled": false
|
||||
},
|
||||
"onStop": {
|
||||
"url": "",
|
||||
"enabled": false
|
||||
},
|
||||
"onFinish": {
|
||||
"url": "",
|
||||
"enabled": false
|
||||
}
|
||||
},
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
// haven't been able to get this to work
|
||||
// it is well discussed in the issues, so should be able to find something
|
||||
// https://playwrightsolutions.com/making-a-post/
|
||||
// https://playwright.dev/docs/api/class-apirequestcontext#api-request-context-fetch
|
||||
// the upload is accepted by backend we receive 400 after upload and parse
|
||||
|
||||
export async function uploadTestDb(request) {
|
||||
const filePath = path.resolve('e2e/tests/fixtures/test-db.json');
|
||||
const file = fs.readFileSync(filePath);
|
||||
|
||||
const response = await request.post('http://localhost:4001/ontime/db?onlyRundown=false', {
|
||||
multipart: {
|
||||
file: {
|
||||
fileName: filePath,
|
||||
mimeType: "application/json",
|
||||
buffer: file,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
+4
-1
@@ -1,3 +1,6 @@
|
||||
{
|
||||
"sourceType": "module"
|
||||
"sourceType": "module",
|
||||
"compilerOptions": {
|
||||
"esModuleInterop": true
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -30,12 +30,12 @@
|
||||
"dist-win": "turbo run dist-win",
|
||||
"dist-mac": "turbo run dist-mac",
|
||||
"dist-linux": "turbo run dist-linux",
|
||||
"test": "vitest",
|
||||
"e2e": "cross-env DEBUG=pw:webserver npx playwright test -c playwright.config.ts",
|
||||
"e2e:i": "npx playwright codegen",
|
||||
"cleanup": "rm -rf node_modules && rm -rf **/node_modules && rm -rf **/**/node_modules"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.32.1",
|
||||
"@playwright/test": "^1.32.3",
|
||||
"@types/node": "^18.11.18",
|
||||
"@typescript-eslint/eslint-plugin": "^5.48.0",
|
||||
"@typescript-eslint/parser": "^5.48.0",
|
||||
|
||||
Generated
+18
-18
@@ -4,7 +4,7 @@ importers:
|
||||
|
||||
.:
|
||||
specifiers:
|
||||
'@playwright/test': ^1.32.1
|
||||
'@playwright/test': ^1.32.3
|
||||
'@types/node': ^18.11.18
|
||||
'@typescript-eslint/eslint-plugin': ^5.48.0
|
||||
'@typescript-eslint/parser': ^5.48.0
|
||||
@@ -16,7 +16,7 @@ importers:
|
||||
turbo: ^1.8.8
|
||||
typescript: ^4.8.3
|
||||
devDependencies:
|
||||
'@playwright/test': 1.32.1
|
||||
'@playwright/test': 1.32.3
|
||||
'@types/node': 18.11.18
|
||||
'@typescript-eslint/eslint-plugin': 5.48.0_k73wpmdolxikpyqun3p36akaaq
|
||||
'@typescript-eslint/parser': 5.48.0_iukboom6ndih5an6iafl45j2fe
|
||||
@@ -2273,7 +2273,7 @@ packages:
|
||||
'@jest/schemas': 29.0.0
|
||||
'@types/istanbul-lib-coverage': 2.0.4
|
||||
'@types/istanbul-reports': 3.0.1
|
||||
'@types/node': 18.11.18
|
||||
'@types/node': 18.15.11
|
||||
'@types/yargs': 17.0.19
|
||||
chalk: 4.1.2
|
||||
dev: true
|
||||
@@ -2363,13 +2363,13 @@ packages:
|
||||
fastq: 1.15.0
|
||||
dev: true
|
||||
|
||||
/@playwright/test/1.32.1:
|
||||
resolution: {integrity: sha512-FTwjCuhlm1qHUGf4hWjfr64UMJD/z0hXYbk+O387Ioe6WdyZQ+0TBDAc6P+pHjx2xCv1VYNgrKbYrNixFWy4Dg==}
|
||||
/@playwright/test/1.32.3:
|
||||
resolution: {integrity: sha512-BvWNvK0RfBriindxhLVabi8BRe3X0J9EVjKlcmhxjg4giWBD/xleLcg2dz7Tx0agu28rczjNIPQWznwzDwVsZQ==}
|
||||
engines: {node: '>=14'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
'@types/node': 18.11.18
|
||||
playwright-core: 1.32.1
|
||||
'@types/node': 18.15.11
|
||||
playwright-core: 1.32.3
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.2
|
||||
dev: true
|
||||
@@ -2826,7 +2826,7 @@ packages:
|
||||
resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==}
|
||||
dependencies:
|
||||
'@types/connect': 3.4.35
|
||||
'@types/node': 18.11.18
|
||||
'@types/node': 18.15.11
|
||||
dev: true
|
||||
|
||||
/@types/cacheable-request/6.0.3:
|
||||
@@ -2834,7 +2834,7 @@ packages:
|
||||
dependencies:
|
||||
'@types/http-cache-semantics': 4.0.1
|
||||
'@types/keyv': 3.1.4
|
||||
'@types/node': 16.18.23
|
||||
'@types/node': 18.15.11
|
||||
'@types/responselike': 1.0.0
|
||||
dev: true
|
||||
|
||||
@@ -2867,7 +2867,7 @@ packages:
|
||||
/@types/connect/3.4.35:
|
||||
resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==}
|
||||
dependencies:
|
||||
'@types/node': 18.11.18
|
||||
'@types/node': 18.15.11
|
||||
dev: true
|
||||
|
||||
/@types/debug/4.1.7:
|
||||
@@ -2883,7 +2883,7 @@ packages:
|
||||
/@types/express-serve-static-core/4.17.33:
|
||||
resolution: {integrity: sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==}
|
||||
dependencies:
|
||||
'@types/node': 18.11.18
|
||||
'@types/node': 18.15.11
|
||||
'@types/qs': 6.9.7
|
||||
'@types/range-parser': 1.2.4
|
||||
dev: true
|
||||
@@ -2946,7 +2946,7 @@ packages:
|
||||
/@types/keyv/3.1.4:
|
||||
resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==}
|
||||
dependencies:
|
||||
'@types/node': 16.18.23
|
||||
'@types/node': 18.15.11
|
||||
dev: true
|
||||
|
||||
/@types/lodash.mergewith/4.6.7:
|
||||
@@ -3043,7 +3043,7 @@ packages:
|
||||
/@types/responselike/1.0.0:
|
||||
resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==}
|
||||
dependencies:
|
||||
'@types/node': 16.18.23
|
||||
'@types/node': 18.15.11
|
||||
dev: true
|
||||
|
||||
/@types/scheduler/0.16.2:
|
||||
@@ -3057,7 +3057,7 @@ packages:
|
||||
resolution: {integrity: sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==}
|
||||
dependencies:
|
||||
'@types/mime': 3.0.1
|
||||
'@types/node': 18.11.18
|
||||
'@types/node': 18.15.11
|
||||
dev: true
|
||||
|
||||
/@types/stack-utils/2.0.1:
|
||||
@@ -3096,7 +3096,7 @@ packages:
|
||||
resolution: {integrity: sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==}
|
||||
requiresBuild: true
|
||||
dependencies:
|
||||
'@types/node': 16.18.23
|
||||
'@types/node': 18.15.11
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
@@ -6160,7 +6160,7 @@ packages:
|
||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||
dependencies:
|
||||
'@jest/types': 29.3.1
|
||||
'@types/node': 18.11.18
|
||||
'@types/node': 18.15.11
|
||||
chalk: 4.1.2
|
||||
ci-info: 3.7.1
|
||||
graceful-fs: 4.2.11
|
||||
@@ -7005,8 +7005,8 @@ packages:
|
||||
pathe: 1.1.0
|
||||
dev: true
|
||||
|
||||
/playwright-core/1.32.1:
|
||||
resolution: {integrity: sha512-KZYUQC10mXD2Am1rGlidaalNGYk3LU1vZqqNk0gT4XPty1jOqgup8KDP8l2CUlqoNKhXM5IfGjWgW37xvGllBA==}
|
||||
/playwright-core/1.32.3:
|
||||
resolution: {integrity: sha512-SB+cdrnu74ZIn5Ogh/8278ngEh9NEEV0vR4sJFmK04h2iZpybfbqBY0bX6+BLYWVdV12JLLI+JEFtSnYgR+mWg==}
|
||||
engines: {node: '>=14'}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
Reference in New Issue
Block a user