mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-11 19:46:16 -08:00
12 files changed
+335
-166
No files matched your search
@@ -8,7 +8,10 @@
|
||||
"Bash(cat:*)",
|
||||
"Bash(npx asar:*)",
|
||||
"Bash(npm run package:app:*)",
|
||||
"Bash(npm run build:backend:*)"
|
||||
"Bash(npm run build:backend:*)",
|
||||
"Bash(pnpm add:*)",
|
||||
"WebFetch(domain:github.com)",
|
||||
"WebFetch(domain:www.npmjs.com)"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
name: 'Build and Test'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build-and-test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '22'
|
||||
- run: git config --global url."https://${{ secrets.PAT }}@github.com/".insteadOf ssh://git@github.com/
|
||||
- run: npm ci
|
||||
- run: npm test -- --coverage
|
||||
- run: bash <(curl -s https://codecov.io/bash)
|
||||
- run: npm run build:prod
|
||||
env:
|
||||
CI: true
|
||||
e2e-tests:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-latest]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '22'
|
||||
- run: git config --global url."https://${{ secrets.PAT }}@github.com/".insteadOf ssh://git@github.com/
|
||||
- run: npm ci
|
||||
# env:
|
||||
# PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
|
||||
- run: npm run build:prod
|
||||
- run: npx playwright install --with-deps
|
||||
#- run: xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run e2e:ci
|
||||
# if: matrix.os == 'ubuntu-latest'
|
||||
# env:
|
||||
# e2e: true
|
||||
- run: npm run e2e:ci
|
||||
env:
|
||||
e2e: true
|
||||
# release:
|
||||
# needs: [build-and-test]
|
||||
# runs-on: ${{ matrix.os }}
|
||||
|
||||
# strategy:
|
||||
# matrix:
|
||||
# os: [macos-latest, ubuntu-latest, windows-latest]
|
||||
|
||||
# steps:
|
||||
# - name: Check out Git repository
|
||||
# uses: actions/checkout@v4
|
||||
|
||||
# - name: Install Node.js, NPM and Yarn
|
||||
# uses: actions/setup-node@v4
|
||||
# with:
|
||||
# node-version: '22'
|
||||
|
||||
# - name: Build Electron app
|
||||
# uses: samuelmeuli/action-electron-builder@v1
|
||||
# with:
|
||||
# # GitHub token, automatically provided to the action
|
||||
# # (No need to define this secret in the repo settings)
|
||||
# github_token: ${{ secrets.github_token }}
|
||||
|
||||
# # If the commit is tagged with a version (e.g. "v1.0.0"),
|
||||
# # release the app after building
|
||||
# release: ${{ startsWith(github.ref, 'refs/tags/v') }}
|
||||
# #- name: Archive production artifacts
|
||||
# # uses: actions/upload-artifact@v3
|
||||
# # with:
|
||||
# # name: dev-release
|
||||
# # path: ./release/**
|
||||
@@ -0,0 +1,63 @@
|
||||
name: 'Cross-Platform E2E Tests'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- nx
|
||||
pull_request:
|
||||
branches:
|
||||
- nx
|
||||
|
||||
jobs:
|
||||
e2e-tests:
|
||||
name: E2E on ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
NX_SKIP_NX_CACHE: true
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '22'
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install Dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Build Backend
|
||||
run: npx nx build electron-backend
|
||||
|
||||
- name: Install Playwright Browsers
|
||||
run: npx playwright install --with-deps
|
||||
|
||||
- name: Run E2E Tests (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
run: xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" npx nx run electron-backend-e2e:e2e
|
||||
env:
|
||||
CI: true
|
||||
|
||||
- name: Run E2E Tests (Windows/Mac)
|
||||
if: runner.os != 'Linux'
|
||||
run: npx nx run electron-backend-e2e:e2e
|
||||
env:
|
||||
CI: true
|
||||
|
||||
- name: Upload Test Results
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: playwright-report-${{ matrix.os }}
|
||||
path: dist/playwright-report/electron-backend-e2e/
|
||||
retention-days: 7
|
||||
@@ -0,0 +1,12 @@
|
||||
import playwright from 'eslint-plugin-playwright';
|
||||
import baseConfig from '../../eslint.config.mjs';
|
||||
|
||||
export default [
|
||||
playwright.configs['flat/recommended'],
|
||||
...baseConfig,
|
||||
{
|
||||
files: ['**/*.ts', '**/*.js'],
|
||||
// Override or add rules here
|
||||
rules: {},
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,47 @@
|
||||
import { defineConfig } from '@playwright/test';
|
||||
|
||||
/**
|
||||
* Playwright configuration for Electron e2e tests.
|
||||
* See https://playwright.dev/docs/test-configuration.
|
||||
*/
|
||||
export default defineConfig({
|
||||
testDir: './src',
|
||||
/* Match .e2e.ts files */
|
||||
testMatch: '**/*.e2e.ts',
|
||||
/* Run tests sequentially since we're testing an Electron app */
|
||||
fullyParallel: false,
|
||||
/* Fail the build on CI if you accidentally left test.only in the source code */
|
||||
forbidOnly: !!process.env['CI'],
|
||||
/* Retry on CI only */
|
||||
retries: process.env['CI'] ? 2 : 0,
|
||||
/* Single worker since we're testing an Electron app */
|
||||
workers: 1,
|
||||
/* Reporter to use */
|
||||
reporter: [
|
||||
['list'],
|
||||
['html', { outputFolder: '../../dist/playwright-report/electron-backend-e2e' }],
|
||||
],
|
||||
/* Shared settings for all the projects below */
|
||||
use: {
|
||||
/* Collect trace when retrying the failed test */
|
||||
trace: 'on-first-retry',
|
||||
/* Screenshots on failure */
|
||||
screenshot: 'on',
|
||||
/* Video on failure */
|
||||
video: 'on-first-retry',
|
||||
},
|
||||
/* Output folder for test artifacts */
|
||||
outputDir: '../../dist/test-results/electron-backend-e2e',
|
||||
/* Timeout for each test */
|
||||
timeout: 60000,
|
||||
/* Timeout for expect() assertions */
|
||||
expect: {
|
||||
timeout: 10000,
|
||||
},
|
||||
projects: [
|
||||
{
|
||||
name: 'electron',
|
||||
use: {},
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "electron-backend-e2e",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"projectType": "application",
|
||||
"sourceRoot": "apps/electron-backend-e2e/src",
|
||||
"implicitDependencies": ["electron-backend"],
|
||||
"targets": {
|
||||
"e2e": {
|
||||
"dependsOn": ["electron-backend:build"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
import {
|
||||
_electron as electron,
|
||||
ElectronApplication,
|
||||
expect,
|
||||
Page,
|
||||
test,
|
||||
} from '@playwright/test';
|
||||
import { existsSync, mkdirSync } from 'fs';
|
||||
import { join, resolve } from 'path';
|
||||
|
||||
/**
|
||||
* Smoke test for the Electron application.
|
||||
* Verifies that the app starts correctly and renders the main window.
|
||||
*/
|
||||
|
||||
let electronApp: ElectronApplication;
|
||||
let mainWindow: Page;
|
||||
|
||||
// Workspace root (where nx.json is located)
|
||||
const workspaceRoot = resolve(__dirname, '../../..');
|
||||
|
||||
// Path to the packaged Electron app main.js file
|
||||
const electronMainPath = join(
|
||||
workspaceRoot,
|
||||
'dist/apps/electron-backend/main.js'
|
||||
);
|
||||
|
||||
// Path for screenshots
|
||||
const screenshotDir = join(
|
||||
workspaceRoot,
|
||||
'dist/test-results/electron-backend-e2e'
|
||||
);
|
||||
|
||||
// Ensure screenshot directory exists
|
||||
if (!existsSync(screenshotDir)) {
|
||||
mkdirSync(screenshotDir, { recursive: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to find the main application window (not DevTools)
|
||||
*/
|
||||
async function findMainWindow(app: ElectronApplication): Promise<Page> {
|
||||
// Wait for windows to be available
|
||||
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||
|
||||
const windows = app.windows();
|
||||
console.log(`Found ${windows.length} window(s)`);
|
||||
|
||||
for (const window of windows) {
|
||||
const title = await window.title();
|
||||
console.log(`Window title: "${title}"`);
|
||||
// Skip DevTools windows
|
||||
if (!title.includes('DevTools')) {
|
||||
return window;
|
||||
}
|
||||
}
|
||||
|
||||
// If no non-DevTools window found, wait for one
|
||||
console.log('Waiting for main window...');
|
||||
return await app.firstWindow();
|
||||
}
|
||||
|
||||
test.describe('Electron App Smoke Test', () => {
|
||||
test.beforeAll(async () => {
|
||||
console.log(`Launching Electron app from: ${electronMainPath}`);
|
||||
console.log(`Platform: ${process.platform}`);
|
||||
console.log(`CI: ${process.env['CI']}`);
|
||||
|
||||
// Check if web build exists
|
||||
const webIndexPath = join(workspaceRoot, 'dist/apps/web/index.html');
|
||||
console.log(`Web index path: ${webIndexPath}`);
|
||||
console.log(`Web index exists: ${existsSync(webIndexPath)}`);
|
||||
|
||||
// Launch the Electron app
|
||||
// On Linux CI, we need to disable sandbox due to permission issues
|
||||
const args = [electronMainPath];
|
||||
if (process.platform === 'linux' && process.env['CI']) {
|
||||
args.unshift('--no-sandbox', '--disable-gpu');
|
||||
}
|
||||
|
||||
electronApp = await electron.launch({
|
||||
args,
|
||||
env: {
|
||||
...process.env,
|
||||
NODE_ENV: 'test',
|
||||
ELECTRON_IS_DEV: '0',
|
||||
},
|
||||
});
|
||||
|
||||
// Find the main application window (not DevTools)
|
||||
mainWindow = await findMainWindow(electronApp);
|
||||
|
||||
// Wait for the window to be fully loaded
|
||||
await mainWindow.waitForLoadState('domcontentloaded');
|
||||
|
||||
// Debug: Log the current URL
|
||||
const url = mainWindow.url();
|
||||
console.log(`Page URL: ${url}`);
|
||||
|
||||
// Wait for Angular to bootstrap and render
|
||||
await mainWindow.waitForSelector('app-root', { timeout: 30000 });
|
||||
|
||||
// Wait for Angular to fully initialize and set the title
|
||||
await mainWindow.waitForFunction(
|
||||
() => document.title.length > 0,
|
||||
{ timeout: 30000 }
|
||||
);
|
||||
|
||||
console.log('Electron app launched successfully');
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
if (electronApp) {
|
||||
await electronApp.close();
|
||||
}
|
||||
});
|
||||
|
||||
test('app should start and display main window', async () => {
|
||||
expect(mainWindow).toBeTruthy();
|
||||
|
||||
await mainWindow.screenshot({
|
||||
path: join(screenshotDir, 'smoke-test-screenshot.png'),
|
||||
fullPage: true,
|
||||
});
|
||||
|
||||
const title = await mainWindow.title();
|
||||
console.log(`Window title: ${title}`);
|
||||
expect(title).toContain('IPTVnator');
|
||||
});
|
||||
|
||||
test('app should have expected window properties', async () => {
|
||||
const isVisible = await electronApp.evaluate(({ BrowserWindow }) => {
|
||||
const mainWindow = BrowserWindow.getAllWindows()[0];
|
||||
return mainWindow ? mainWindow.isVisible() : false;
|
||||
});
|
||||
expect(isVisible).toBe(true);
|
||||
|
||||
const bounds = await electronApp.evaluate(({ BrowserWindow }) => {
|
||||
const mainWindow = BrowserWindow.getAllWindows()[0];
|
||||
return mainWindow ? mainWindow.getBounds() : null;
|
||||
});
|
||||
expect(bounds).not.toBeNull();
|
||||
expect(bounds?.width).toBeGreaterThan(800);
|
||||
expect(bounds?.height).toBeGreaterThan(600);
|
||||
|
||||
await mainWindow.screenshot({
|
||||
path: join(screenshotDir, 'window-properties-screenshot.png'),
|
||||
});
|
||||
});
|
||||
|
||||
test('app should render main content', async () => {
|
||||
// Wait for app-root to have actual content
|
||||
await mainWindow.waitForFunction(
|
||||
() => {
|
||||
const appRoot = document.querySelector('app-root');
|
||||
return appRoot && appRoot.innerHTML.trim().length > 0;
|
||||
},
|
||||
{ timeout: 30000 }
|
||||
);
|
||||
|
||||
const bodyContent = await mainWindow.locator('body').innerHTML();
|
||||
expect(bodyContent.length).toBeGreaterThan(0);
|
||||
|
||||
await mainWindow.screenshot({
|
||||
path: join(screenshotDir, 'rendered-content-screenshot.png'),
|
||||
fullPage: true,
|
||||
});
|
||||
|
||||
console.log('Smoke test completed successfully');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"sourceMap": false,
|
||||
"module": "commonjs",
|
||||
"strict": true,
|
||||
"noImplicitOverride": true,
|
||||
"noPropertyAccessFromIndexSignature": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts",
|
||||
"**/*.js",
|
||||
"playwright.config.ts",
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.spec.js",
|
||||
"src/**/*.test.ts",
|
||||
"src/**/*.test.js",
|
||||
"src/**/*.d.ts",
|
||||
"src/**/*.e2e.ts"
|
||||
]
|
||||
}
|
||||
@@ -156,7 +156,7 @@ export default class App {
|
||||
|
||||
private static loadMainWindow() {
|
||||
// load the index.html of the app.
|
||||
if (!App.application.isPackaged) {
|
||||
if (App.isDevelopmentMode()) {
|
||||
App.mainWindow.loadURL(`http://localhost:${rendererAppPort}`);
|
||||
App.mainWindow.webContents.openDevTools();
|
||||
} else {
|
||||
|
||||
Generated
-49
@@ -130,8 +130,6 @@
|
||||
"ng-mocks": "14.14.0",
|
||||
"nx": "22.3.3",
|
||||
"nx-electron": "^21.0.1",
|
||||
"playwright": "1.56.1",
|
||||
"playwright-core": "1.56.1",
|
||||
"prettier": "^3.6.2",
|
||||
"semantic-release": "24.2.9",
|
||||
"ts-jest": "^29.4.5",
|
||||
@@ -32101,53 +32099,6 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright": {
|
||||
"version": "1.56.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.56.1.tgz",
|
||||
"integrity": "sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright-core": "1.56.1"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright-core": {
|
||||
"version": "1.56.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.1.tgz",
|
||||
"integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"playwright-core": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright/node_modules/fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/plist": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz",
|
||||
|
||||
@@ -154,8 +154,6 @@
|
||||
"ng-mocks": "14.14.0",
|
||||
"nx": "22.3.3",
|
||||
"nx-electron": "^21.0.1",
|
||||
"playwright": "1.56.1",
|
||||
"playwright-core": "1.56.1",
|
||||
"prettier": "^3.6.2",
|
||||
"semantic-release": "24.2.9",
|
||||
"ts-jest": "^29.4.5",
|
||||
|
||||
Generated
-24
@@ -342,12 +342,6 @@ importers:
|
||||
nx-electron:
|
||||
specifier: ^21.0.1
|
||||
version: 21.0.1(@nx/workspace@22.3.3(@swc-node/register@1.9.2(@swc/core@1.5.29(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.5.29(@swc/helpers@0.5.18)))(@swc/core@1.5.29(@swc/helpers@0.5.18))(electron@39.2.7)(esbuild@0.27.0)(rxjs@7.8.2)(typescript@5.9.3)
|
||||
playwright:
|
||||
specifier: 1.56.1
|
||||
version: 1.56.1
|
||||
playwright-core:
|
||||
specifier: 1.56.1
|
||||
version: 1.56.1
|
||||
prettier:
|
||||
specifier: ^3.6.2
|
||||
version: 3.7.4
|
||||
@@ -8296,21 +8290,11 @@ packages:
|
||||
resolution: {integrity: sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==}
|
||||
engines: {node: '>=14.16'}
|
||||
|
||||
playwright-core@1.56.1:
|
||||
resolution: {integrity: sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
playwright-core@1.57.0:
|
||||
resolution: {integrity: sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
playwright@1.56.1:
|
||||
resolution: {integrity: sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
playwright@1.57.0:
|
||||
resolution: {integrity: sha512-ilYQj1s8sr2ppEJ2YVadYBN0Mb3mdo9J0wQ+UuDhzYqURwSoW4n1Xs5vs7ORwgDGmyEh33tRMeS8KhdkMoLXQw==}
|
||||
engines: {node: '>=18'}
|
||||
@@ -19755,16 +19739,8 @@ snapshots:
|
||||
dependencies:
|
||||
find-up: 6.3.0
|
||||
|
||||
playwright-core@1.56.1: {}
|
||||
|
||||
playwright-core@1.57.0: {}
|
||||
|
||||
playwright@1.56.1:
|
||||
dependencies:
|
||||
playwright-core: 1.56.1
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.2
|
||||
|
||||
playwright@1.57.0:
|
||||
dependencies:
|
||||
playwright-core: 1.57.0
|
||||
|
||||
Reference in new issue
Block a user