From 9edbe049aa4c4ba3b57fccc2d00dc10beadfcabd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krist=C3=B3f=20Marussy?= Date: Tue, 31 May 2022 17:05:30 +0200 Subject: build: run integration tests in CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kristóf Marussy --- .gitlab-ci.yml | 19 ++++++ package.json | 5 +- .../config/impl/__tests__/ConfigFile.integ.test.ts | 34 ++++++----- packages/test-utils/package.json | 4 ++ packages/test-utils/src/index.ts | 7 +-- packages/test-utils/src/testIf.ts | 70 ++++++++++++++++++++++ yarn.lock | 2 + 7 files changed, 121 insertions(+), 20 deletions(-) create mode 100644 packages/test-utils/src/testIf.ts diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f129977..d38a1bc 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -7,6 +7,7 @@ cache: stages: - code-quality - test + - integ - build default: @@ -40,6 +41,23 @@ test: path: coverage/test/cobertura-coverage.xml junit: junit.xml +integ: + stage: integ + coverage: /All files[^|]*\|[^|]*\s+([\d\.]+)/ + before_script: + - apt-get update + - apt-get install -y dbus-x11 libasound2 libatk1.0-0 libatk-bridge2.0-0 libcups2 libgbm1 libgtk-3-0 libnss3 xvfb + - yarn install --immutable + script: + - yarn test:integ:xvfb:ci + - yarn test:integ:check-exit + artifacts: + reports: + coverage_report: + coverage_format: cobertura + path: coverage/integ/cobertura-coverage.xml + junit: junit.xml + # TODO: GitlabCI free runners are only for linux - need to investigate for macos and windows artifacts build: stage: build @@ -47,6 +65,7 @@ build: - yarn compile # TODO: Need to publish the built distributable file artifacts: + expire_in: 1 week paths: - dist/ exclude: diff --git a/package.json b/package.json index 625f3b6..bd72a39 100644 --- a/package.json +++ b/package.json @@ -21,11 +21,12 @@ "scripts": { "clean": "rimraf coverage dist 'packages/*/dist' 'packages/*/*.tsbuildinfo' .vite", "test": "node --experimental-vm-modules --no-warnings $(yarn bin jest)", - "test:ci": "yarn test --ci --coverage --reporters=default --reporters=jest-junit", + "test:ci": "cross-env DISABLE_GPU=true JEST_JUNIT_SUITE_NAME=\"{filepath}\" JEST_JUNIT_CLASSNAME=\"{filepath}\" JEST_JUNIT_ADD_FILE_ATTRIBUTE=true JEST_JUNIT_REPORT_TEST_SUITE_ERRORS=true yarn test --ci --coverage --reporters=default --reporters=jest-junit", "test:integ": "electron scripts/electronJest.cjs --user-data-dir=userDataDir/integ --config=jest.integ.config.cjs --runInBand", "test:integ:xvfb": "cross-env DISABLE_GPU=true xvfb-run -s \"-screen 0 1920x1080x24\" electron scripts/electronJest.cjs --user-data-dir=userDataDir/integ --disable-features=WebRTCPipeWireCapturer --ozone-platform=x11 --config=jest.integ.config.cjs --runInBand", "test:integ:ci": "cross-env DISABLE_GPU=true yarn test:integ --ci --coverage --reporters=default --reporters=jest-junit", - "test:integ:xvfb:ci": "yarn test:integ:xvfb --ci --coverage --reporters=default --reporters=jest-junit", + "test:integ:xvfb:ci": "cross-env DISABLE_GPU=true JEST_JUNIT_SUITE_NAME=\"{filepath}\" JEST_JUNIT_CLASSNAME=\"{filepath}\" JEST_JUNIT_ADD_FILE_ATTRIBUTE=true JEST_JUNIT_REPORT_TEST_SUITE_ERRORS=true xvfb-run -s \"-screen 0 1920x1080x24\" electron scripts/electronJest.cjs --no-sandbox --user-data-dir=userDataDir/integ --disable-features=WebRTCPipeWireCapturer --ozone-platform=x11 --config=jest.integ.config.cjs --runInBand --ci --coverage --reporters=default --reporters=jest-junit", + "test:integ:check-exit": "grep -qF 'failures=\"0\" errors=\"0\"' junit.xml", "build": "node scripts/build.js", "precompile": "cross-env MODE=production yarn run build", "compile": "yarn precompile && yarn compile:electron-builder", diff --git a/packages/main/src/infrastructure/config/impl/__tests__/ConfigFile.integ.test.ts b/packages/main/src/infrastructure/config/impl/__tests__/ConfigFile.integ.test.ts index dd4aaaa..c443d99 100644 --- a/packages/main/src/infrastructure/config/impl/__tests__/ConfigFile.integ.test.ts +++ b/packages/main/src/infrastructure/config/impl/__tests__/ConfigFile.integ.test.ts @@ -29,10 +29,11 @@ import { utimes, writeFile, } from 'node:fs/promises'; -import { tmpdir } from 'node:os'; +import { platform, tmpdir, userInfo } from 'node:os'; import path from 'node:path'; import { jest } from '@jest/globals'; +import { testIf } from '@sophie/test-utils'; import { mocked } from 'jest-mock'; import Disposer from '../../../../utils/Disposer.js'; @@ -249,19 +250,24 @@ describe('watchConfig', () => { expect(callback).toHaveBeenCalled(); }); - test('handles other filesystem errors', async () => { - const { mode } = await stat(userDataDir!); - await writeFile(configFilePath, 'Hi Mars!', 'utf8'); - // Remove permission to force a filesystem error. - // eslint-disable-next-line no-bitwise -- Compute reduced permissions. - await chmod(userDataDir!, mode & 0o666); - try { - await catchUpWithFilesystem(); - expect(callback).not.toHaveBeenCalled(); - } finally { - await chmod(userDataDir!, mode); - } - }); + // We can only cause a filesystem error by changing permissions if we run on a POSIX-like + // system and we aren't root (i.e., not in CI). + testIf(platform() !== 'win32' && userInfo().uid !== 0)( + 'handles other filesystem errors', + async () => { + const { mode } = await stat(userDataDir!); + await writeFile(configFilePath, 'Hi Mars!', 'utf8'); + // Remove permission to force a filesystem error. + // eslint-disable-next-line no-bitwise -- Compute reduced permissions. + await chmod(userDataDir!, mode & 0o666); + try { + await catchUpWithFilesystem(); + expect(callback).not.toHaveBeenCalled(); + } finally { + await chmod(userDataDir!, mode); + } + }, + ); test('does not notify when the modification date is prior to the last write', async () => { await repository.writeConfig('Hello World!'); diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 93f1626..8243cc5 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -10,6 +10,10 @@ "types": "yarn g:types" }, "dependencies": { + "@jest/globals": "^28.1.0", "type-fest": "^2.13.0" + }, + "devDependencies": { + "@jest/types": "^28.1.0" } } diff --git a/packages/test-utils/src/index.ts b/packages/test-utils/src/index.ts index 52ac98d..528b872 100644 --- a/packages/test-utils/src/index.ts +++ b/packages/test-utils/src/index.ts @@ -18,8 +18,7 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -/* - eslint-disable-next-line import/prefer-default-export -- - Keep API consistent for more helpers in the future. -*/ export { default as fake } from './fake.js'; + +export type { TestIf, TestIfConcurrent } from './testIf.js'; +export { default as testIf } from './testIf.js'; diff --git a/packages/test-utils/src/testIf.ts b/packages/test-utils/src/testIf.ts new file mode 100644 index 0000000..2309ddc --- /dev/null +++ b/packages/test-utils/src/testIf.ts @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2022 Kristóf Marussy + * + * This file is part of Sophie. + * + * Sophie is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { test } from '@jest/globals'; +import type { Global } from '@jest/types'; + +export interface TestIfConcurrent { + (condition: boolean): Global.ItConcurrentBase; + + only(condition: boolean): Global.ItConcurrentBase; + + skip(condition: boolean): Global.ItConcurrentBase; +} + +export interface TestIf { + (condition: boolean): Global.ItBase; + + only(condition: boolean): Global.ItBase; + + skip(condition: boolean): Global.ItBase; + + concurrent: TestIfConcurrent; +} + +const testIfConcurrent: TestIfConcurrent = function concurrent( + condition: boolean, +) { + return condition ? test.concurrent : test.concurrent.skip; +}; + +testIfConcurrent.only = function only() { + return test.concurrent.only; +}; + +testIfConcurrent.skip = function skip() { + return test.concurrent.skip; +}; + +const testIf: TestIf = function testIf(condition: boolean) { + return condition ? test : test.skip; +}; + +testIf.only = function only() { + return test.only; +}; + +testIf.skip = function skip() { + return test.skip; +}; + +testIf.concurrent = testIfConcurrent; + +export default testIf; diff --git a/yarn.lock b/yarn.lock index 065cac8..86a70f6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1434,6 +1434,8 @@ __metadata: version: 0.0.0-use.local resolution: "@sophie/test-utils@workspace:packages/test-utils" dependencies: + "@jest/globals": ^28.1.0 + "@jest/types": ^28.1.0 type-fest: ^2.13.0 languageName: unknown linkType: soft -- cgit v1.2.3