mirror of
https://github.com/imputnet/cobalt.git
synced 2025-07-18 11:18:28 +00:00
WIP tests
This commit is contained in:
parent
b04c204492
commit
9106b4f511
@ -119,6 +119,9 @@ importers:
|
|||||||
'@fontsource/redaction-10':
|
'@fontsource/redaction-10':
|
||||||
specifier: ^5.0.2
|
specifier: ^5.0.2
|
||||||
version: 5.0.2
|
version: 5.0.2
|
||||||
|
'@playwright/test':
|
||||||
|
specifier: ^1.47.1
|
||||||
|
version: 1.47.1
|
||||||
'@sveltejs/adapter-static':
|
'@sveltejs/adapter-static':
|
||||||
specifier: ^3.0.2
|
specifier: ^3.0.2
|
||||||
version: 3.0.2(@sveltejs/kit@2.5.19(@sveltejs/vite-plugin-svelte@3.1.1(svelte@4.2.18)(vite@5.3.5(@types/node@20.14.14)))(svelte@4.2.18)(vite@5.3.5(@types/node@20.14.14)))
|
version: 3.0.2(@sveltejs/kit@2.5.19(@sveltejs/vite-plugin-svelte@3.1.1(svelte@4.2.18)(vite@5.3.5(@types/node@20.14.14)))(svelte@4.2.18)(vite@5.3.5(@types/node@20.14.14)))
|
||||||
@ -135,7 +138,7 @@ importers:
|
|||||||
specifier: ^2.1.25
|
specifier: ^2.1.25
|
||||||
version: 2.1.25
|
version: 2.1.25
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^20.14.10
|
specifier: ^20.14.14
|
||||||
version: 20.14.14
|
version: 20.14.14
|
||||||
compare-versions:
|
compare-versions:
|
||||||
specifier: ^6.1.0
|
specifier: ^6.1.0
|
||||||
@ -561,6 +564,11 @@ packages:
|
|||||||
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
|
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
|
|
||||||
|
'@playwright/test@1.47.1':
|
||||||
|
resolution: {integrity: sha512-dbWpcNQZ5nj16m+A5UNScYx7HX5trIy7g4phrcitn+Nk83S32EBX/CLU4hiF4RGKX/yRc93AAqtfaXB7JWBd4Q==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
'@polka/url@1.0.0-next.25':
|
'@polka/url@1.0.0-next.25':
|
||||||
resolution: {integrity: sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==}
|
resolution: {integrity: sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==}
|
||||||
|
|
||||||
@ -1320,6 +1328,11 @@ packages:
|
|||||||
fs.realpath@1.0.0:
|
fs.realpath@1.0.0:
|
||||||
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
|
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
|
||||||
|
|
||||||
|
fsevents@2.3.2:
|
||||||
|
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
|
||||||
|
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
fsevents@2.3.3:
|
fsevents@2.3.3:
|
||||||
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
||||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||||
@ -1749,6 +1762,16 @@ packages:
|
|||||||
resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==}
|
resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
|
|
||||||
|
playwright-core@1.47.1:
|
||||||
|
resolution: {integrity: sha512-i1iyJdLftqtt51mEk6AhYFaAJCDx0xQ/O5NU8EKaWFgMjItPVma542Nh/Aq8aLCjIJSzjaiEQGW/nyqLkGF1OQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
playwright@1.47.1:
|
||||||
|
resolution: {integrity: sha512-SUEKi6947IqYbKxRiqnbUobVZY4bF1uu+ZnZNJX9DfU1tlf2UhWfvVjLf01pQx9URsOr18bFVUKXmanYWhbfkw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
postcss-load-config@6.0.1:
|
postcss-load-config@6.0.1:
|
||||||
resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==}
|
resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==}
|
||||||
engines: {node: '>= 18'}
|
engines: {node: '>= 18'}
|
||||||
@ -2525,6 +2548,10 @@ snapshots:
|
|||||||
'@pkgjs/parseargs@0.11.0':
|
'@pkgjs/parseargs@0.11.0':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
'@playwright/test@1.47.1':
|
||||||
|
dependencies:
|
||||||
|
playwright: 1.47.1
|
||||||
|
|
||||||
'@polka/url@1.0.0-next.25': {}
|
'@polka/url@1.0.0-next.25': {}
|
||||||
|
|
||||||
'@rollup/rollup-android-arm-eabi@4.19.2':
|
'@rollup/rollup-android-arm-eabi@4.19.2':
|
||||||
@ -3342,6 +3369,9 @@ snapshots:
|
|||||||
|
|
||||||
fs.realpath@1.0.0: {}
|
fs.realpath@1.0.0: {}
|
||||||
|
|
||||||
|
fsevents@2.3.2:
|
||||||
|
optional: true
|
||||||
|
|
||||||
fsevents@2.3.3:
|
fsevents@2.3.3:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@ -3709,6 +3739,14 @@ snapshots:
|
|||||||
|
|
||||||
pirates@4.0.6: {}
|
pirates@4.0.6: {}
|
||||||
|
|
||||||
|
playwright-core@1.47.1: {}
|
||||||
|
|
||||||
|
playwright@1.47.1:
|
||||||
|
dependencies:
|
||||||
|
playwright-core: 1.47.1
|
||||||
|
optionalDependencies:
|
||||||
|
fsevents: 2.3.2
|
||||||
|
|
||||||
postcss-load-config@6.0.1(postcss@8.4.40):
|
postcss-load-config@6.0.1(postcss@8.4.40):
|
||||||
dependencies:
|
dependencies:
|
||||||
lilconfig: 3.1.2
|
lilconfig: 3.1.2
|
||||||
|
5
web/.gitignore
vendored
5
web/.gitignore
vendored
@ -6,3 +6,8 @@
|
|||||||
# vite
|
# vite
|
||||||
vite.config.js.timestamp-*
|
vite.config.js.timestamp-*
|
||||||
vite.config.ts.timestamp-*
|
vite.config.ts.timestamp-*
|
||||||
|
node_modules/
|
||||||
|
/test-results/
|
||||||
|
/playwright-report/
|
||||||
|
/blob-report/
|
||||||
|
/playwright/.cache/
|
||||||
|
@ -8,7 +8,10 @@
|
|||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
|
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||||
|
"test": "playwright test",
|
||||||
|
"test:headfull": "playwright test --headed",
|
||||||
|
"test:withui": "playwright test --ui"
|
||||||
},
|
},
|
||||||
"license": "CC-BY-NC-SA-4.0",
|
"license": "CC-BY-NC-SA-4.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -26,12 +29,13 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.5.0",
|
"@eslint/js": "^9.5.0",
|
||||||
"@fontsource/redaction-10": "^5.0.2",
|
"@fontsource/redaction-10": "^5.0.2",
|
||||||
|
"@playwright/test": "^1.47.1",
|
||||||
"@sveltejs/adapter-static": "^3.0.2",
|
"@sveltejs/adapter-static": "^3.0.2",
|
||||||
"@sveltejs/kit": "^2.0.0",
|
"@sveltejs/kit": "^2.0.0",
|
||||||
"@sveltejs/vite-plugin-svelte": "^3.0.0",
|
"@sveltejs/vite-plugin-svelte": "^3.0.0",
|
||||||
"@types/eslint__js": "^8.42.3",
|
"@types/eslint__js": "^8.42.3",
|
||||||
"@types/fluent-ffmpeg": "^2.1.25",
|
"@types/fluent-ffmpeg": "^2.1.25",
|
||||||
"@types/node": "^20.14.10",
|
"@types/node": "^20.14.14",
|
||||||
"compare-versions": "^6.1.0",
|
"compare-versions": "^6.1.0",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"glob": "^10.4.5",
|
"glob": "^10.4.5",
|
||||||
|
44
web/playwright.config.ts
Normal file
44
web/playwright.config.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import { defineConfig, devices } from '@playwright/test';
|
||||||
|
|
||||||
|
// See https://playwright.dev/docs/test-configuration.
|
||||||
|
export default defineConfig({
|
||||||
|
testDir: './tests',
|
||||||
|
fullyParallel: true,
|
||||||
|
forbidOnly: !!process.env.CI,
|
||||||
|
retries: process.env.CI ? 2 : 0,
|
||||||
|
workers: process.env.CI ? 1 : undefined,
|
||||||
|
reporter: 'html',
|
||||||
|
use: {
|
||||||
|
trace: 'on-first-retry',
|
||||||
|
baseURL: 'https://localhost:5173',
|
||||||
|
ignoreHTTPSErrors: true, // Cobalt uses a self-signed certificate in development
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Configure projects for major browsers */
|
||||||
|
projects: [
|
||||||
|
{
|
||||||
|
name: 'chromium',
|
||||||
|
use: { ...devices['Desktop Chrome'] },
|
||||||
|
},
|
||||||
|
|
||||||
|
// {
|
||||||
|
// name: 'firefox',
|
||||||
|
// use: { ...devices['Desktop Firefox'] },
|
||||||
|
// },
|
||||||
|
|
||||||
|
// {
|
||||||
|
// name: 'webkit',
|
||||||
|
// use: { ...devices['Desktop Safari'] },
|
||||||
|
// },
|
||||||
|
|
||||||
|
// Test on mobile devices (might be useful in the future)?
|
||||||
|
// {
|
||||||
|
// name: 'Mobile Chrome',
|
||||||
|
// use: { ...devices['Pixel 5'] },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: 'Mobile Safari',
|
||||||
|
// use: { ...devices['iPhone 12'] },
|
||||||
|
// },
|
||||||
|
],
|
||||||
|
});
|
@ -1,13 +1,16 @@
|
|||||||
import { get } from "svelte/store";
|
import { get } from 'svelte/store';
|
||||||
|
|
||||||
import env, { apiURL } from "$lib/env";
|
import env, { apiURL } from '$lib/env';
|
||||||
import settings from "$lib/state/settings";
|
import settings from '$lib/state/settings';
|
||||||
|
|
||||||
export const currentApiURL = () => {
|
export const currentApiURL = () => {
|
||||||
const processingSettings = get(settings).processing;
|
const processingSettings = get(settings).processing;
|
||||||
const customInstanceURL = processingSettings.customInstanceURL;
|
const customInstanceURL = processingSettings.customInstanceURL;
|
||||||
|
|
||||||
if (processingSettings.enableCustomInstances && customInstanceURL.length > 0) {
|
if (
|
||||||
|
processingSettings.enableCustomInstances &&
|
||||||
|
customInstanceURL.length > 0
|
||||||
|
) {
|
||||||
return new URL(customInstanceURL).origin;
|
return new URL(customInstanceURL).origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -16,4 +19,4 @@ export const currentApiURL = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return new URL(apiURL).origin;
|
return new URL(apiURL).origin;
|
||||||
}
|
};
|
||||||
|
120
web/tests/home.spec.ts
Normal file
120
web/tests/home.spec.ts
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
|
||||||
|
const VIDEO_TEST_LINK = 'https://www.youtube.com/watch?v=dQw4w9WgXcQ'; // :3
|
||||||
|
|
||||||
|
// Before each test, open the page (/) in the browser and wait for the
|
||||||
|
// page to load.
|
||||||
|
test.beforeEach(async ({ page }) => {
|
||||||
|
await page.goto('/');
|
||||||
|
await page.waitForLoadState('networkidle', { timeout: 10000 });
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test the branding of the page.
|
||||||
|
test('branding', async ({ page }) => {
|
||||||
|
// Page has a tile of "cobalt"
|
||||||
|
const title = await page.title();
|
||||||
|
expect(title).toBe('cobalt');
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if the omnibar is present on the page and has correct branding.
|
||||||
|
* IDs: omnibox, meowbalt (branding), cobalt-save (root main tag)
|
||||||
|
*/
|
||||||
|
const requiredOmniBarElements = ['omnibox', 'cobalt-save'];
|
||||||
|
for (const element of requiredOmniBarElements) {
|
||||||
|
expect(await page.isVisible(`#${element}`)).toBe(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure meowbalt is in the correct default state (visible, class set to "meowbalt smile")
|
||||||
|
// note: meowbalt is a class, not an id
|
||||||
|
const meowbalt = await page.$('.meowbalt');
|
||||||
|
expect(await meowbalt?.isVisible()).toBe(true);
|
||||||
|
expect(await meowbalt?.getAttribute('class')).toContain('meowbalt smile');
|
||||||
|
expect(await meowbalt?.getAttribute('src')).toBe('/meowbalt/smile.png');
|
||||||
|
|
||||||
|
// Aria-hidden attribute is set to true, alt = "meowbalt"
|
||||||
|
expect(await meowbalt?.getAttribute('aria-hidden')).toBe('true');
|
||||||
|
expect(await meowbalt?.getAttribute('alt')).toBe('meowbalt');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Omnibar related tests
|
||||||
|
test('omnibar', async ({ page }) => {
|
||||||
|
// Check if the omnibar is present on the page
|
||||||
|
expect(await page.isVisible('#omnibox')).toBe(true);
|
||||||
|
|
||||||
|
// Input field is present and has the correct placeholder
|
||||||
|
const input = await page.$('#omnibox input');
|
||||||
|
expect(await input?.isVisible()).toBe(true);
|
||||||
|
expect(await input?.getAttribute('placeholder')).toBe(
|
||||||
|
'paste the link here',
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check that all buttons can be clicked #action-container (besides the first one and the last one)
|
||||||
|
const buttons = await (
|
||||||
|
await page.$$('#action-container button')
|
||||||
|
).slice(1, -1);
|
||||||
|
for (const button of buttons) {
|
||||||
|
await button.click();
|
||||||
|
|
||||||
|
// Check if the button has the "selected" class after clicking
|
||||||
|
expect(await button.getAttribute('class')).toContain('active');
|
||||||
|
|
||||||
|
// Make sure the aria-pressed attribute is set to true
|
||||||
|
expect(await button.getAttribute('aria-pressed')).toBe('true');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('supported services', async ({ page }) => {
|
||||||
|
// Check if the supported services are present on the page
|
||||||
|
expect(await page.isVisible('#supported-services')).toBe(true);
|
||||||
|
|
||||||
|
// Click the services-button and expect the dropdown to be visible (services-popover)
|
||||||
|
// Visibility of the popover is when the popover has the "expanded" class
|
||||||
|
const servicesButton = await page.$('#services-button');
|
||||||
|
const servicesPopover = await page.$('#services-popover');
|
||||||
|
await servicesButton?.click();
|
||||||
|
|
||||||
|
// Check if the services popover is visible
|
||||||
|
expect(await servicesPopover?.getAttribute('class')).toContain('expanded');
|
||||||
|
await servicesButton?.click();
|
||||||
|
expect(await servicesPopover?.getAttribute('class')).not.toContain(
|
||||||
|
'expanded',
|
||||||
|
);
|
||||||
|
|
||||||
|
// Now open the services popover and ensure skeleton is present
|
||||||
|
await servicesButton?.click();
|
||||||
|
|
||||||
|
// Get all the skeleton elements
|
||||||
|
const skeletonElements = await page.$$('#services-popover .skeleton');
|
||||||
|
expect(skeletonElements.length).toBeGreaterThan(0);
|
||||||
|
|
||||||
|
// Now wait for the services to load and ensure the skeleton is gone (max of 10 seconds)
|
||||||
|
await page.waitForSelector('#services-popover .service-item', {
|
||||||
|
state: 'attached',
|
||||||
|
timeout: 10000,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('download example', async ({ page }) => {
|
||||||
|
// Get the input field and set the value to the test link
|
||||||
|
const input = await page.$('#omnibox input');
|
||||||
|
await input?.fill(VIDEO_TEST_LINK);
|
||||||
|
|
||||||
|
// Click the download button
|
||||||
|
const downloadButton = await page.$('#download-button');
|
||||||
|
await downloadButton?.click();
|
||||||
|
|
||||||
|
// Wait for the network request to api.cobalt.tools to finish
|
||||||
|
const req = await page.waitForRequest('**/api.cobalt.tools/');
|
||||||
|
const rsp = await req.response();
|
||||||
|
expect(rsp).not.toBe(null);
|
||||||
|
|
||||||
|
// Ensure we have a 200 OK and a valid JSON response
|
||||||
|
expect(rsp!.status()).toBe(200);
|
||||||
|
const json = await rsp!.json();
|
||||||
|
|
||||||
|
// Json should contain the following keys: "status", "url", "and filename"
|
||||||
|
const props = ['status', 'url', 'filename'];
|
||||||
|
for (const prop of props) {
|
||||||
|
expect(json).toHaveProperty(prop);
|
||||||
|
}
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user