Migrate web builds from Vue CLI to Vite
This commit changes the web application's build, transpilation and minification process from Vue CLI to Vite. This shift paves the way for a full migration to Vite as the primary build tool (#230). Configuration changes: - `.vscode/extensions.json`: Update recommended plugins, replacing unmaintained ones with official recommendations. - Legacy browser support: - Use `@vitejs/plugin-legacy` to transpile for older browsers. - Remove `core-js` dependency and `babel.config.cjs` configuration as they're now handled by the legacy plugin. - Delete `@babel/preset-typescript` and `@babel/preset-typescript` dependencies as legacy plugin handles babel dependencies by default. - Add `terser` dependency that's used by the legacy plugin for minification, as per Vite's official documentation. - `tsconfig.json`: - Remove obsolete `webpack-env` types. - Add `"resolveJsonModule": true` to be able to read JSON files in right way. - Use correct casing as configuration values. - Simplify `lib` to align with Vite and Vue starter configuration. - Add `"skipLibCheck": true` as `npm run build` now runs `tsc` which fails on inconsistent typings inside `node_modules` due to npm's weak dependency resoultion. - PostCSS: - Add `autoprefixer` as dependency, no longer installed by Vue CLI. - Epxlicitly added `postcss` as dependency to anticipate potential peer dependency changes. - Remove related `@vue/cli` dependencies. - Remove `sass-loader` as Vite has native CSS preprocessing support. - Run integration tests with `jsdom` environment so `window` object can be used. Client-side changes: - Abstract build tool specific environment variable population. Environment variables were previously populated by Vue CLI and now by Vite but not having an abstraction caused issues. This abstraction solves build errors and allows easier future migrations and testing. - Change Vue CLI-specific `~@` aliases to `@` to be able to compile with Vite. - Update types in LiquorTree to satisfy `tsc`. - Remove Vue CLI-specific workaround from `src/presentation/main.ts`. Restructuring: - Move `public/` to `presentation/` to align with the layered structure, which was not possible with Vue CLI. - Move `index.html` to web root instead of having it inside `public/` to align with official recommended structure. - Move logic shared by both integration and unit tests to `tests/shared`. - Move logo creation script to `scripts/` and its npm command to include `build` to align with rest of the structure.
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
/* eslint-disable max-classes-per-file */
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import type { CollectionData } from '@/application/collections/';
|
||||
import { VueAppEnvironment, parseProjectInformation } from '@/application/Parser/ProjectInformationParser';
|
||||
import { parseProjectInformation } from '@/application/Parser/ProjectInformationParser';
|
||||
import { CategoryCollectionParserType, parseApplication } from '@/application/Parser/ApplicationParser';
|
||||
import { IAppMetadata } from '@/infrastructure/Metadata/IAppMetadata';
|
||||
import WindowsData from '@/application/collections/windows.yaml';
|
||||
import MacOsData from '@/application/collections/macos.yaml';
|
||||
import LinuxData from '@/application/collections/linux.yaml';
|
||||
@@ -12,9 +13,9 @@ import { ICategoryCollection } from '@/domain/ICategoryCollection';
|
||||
import { OperatingSystem } from '@/domain/OperatingSystem';
|
||||
import { getEnumValues } from '@/application/Common/Enum';
|
||||
import { CategoryCollectionStub } from '@tests/unit/shared/Stubs/CategoryCollectionStub';
|
||||
import { getProcessEnvironmentStub } from '@tests/unit/shared/Stubs/ProcessEnvironmentStub';
|
||||
import { CollectionDataStub } from '@tests/unit/shared/Stubs/CollectionDataStub';
|
||||
import { getAbsentCollectionTestCases, AbsentObjectTestCases } from '@tests/unit/shared/TestCases/AbsentTests';
|
||||
import { AppMetadataStub } from '@tests/unit/shared/Stubs/AppMetadataStub';
|
||||
|
||||
describe('ApplicationParser', () => {
|
||||
describe('parseApplication', () => {
|
||||
@@ -41,7 +42,7 @@ describe('ApplicationParser', () => {
|
||||
describe('processEnv', () => {
|
||||
it('used to parse expected project information', () => {
|
||||
// arrange
|
||||
const env = getProcessEnvironmentStub();
|
||||
const env = new AppMetadataStub();
|
||||
const expected = parseProjectInformation(env);
|
||||
const parserSpy = new CategoryCollectionParserSpy();
|
||||
const parserMock = parserSpy.mockParser();
|
||||
@@ -138,7 +139,7 @@ class ApplicationParserBuilder {
|
||||
private categoryCollectionParser: CategoryCollectionParserType = new CategoryCollectionParserSpy()
|
||||
.mockParser();
|
||||
|
||||
private environment: VueAppEnvironment = getProcessEnvironmentStub();
|
||||
private environment: IAppMetadata = new AppMetadataStub();
|
||||
|
||||
private collectionsData: CollectionData[] = [new CollectionDataStub()];
|
||||
|
||||
@@ -150,7 +151,7 @@ class ApplicationParserBuilder {
|
||||
}
|
||||
|
||||
public withEnvironment(
|
||||
environment: VueAppEnvironment,
|
||||
environment: IAppMetadata,
|
||||
): this {
|
||||
this.environment = environment;
|
||||
return this;
|
||||
|
||||
@@ -1,59 +1,59 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { VueAppEnvironmentKeys, parseProjectInformation } from '@/application/Parser/ProjectInformationParser';
|
||||
import { getProcessEnvironmentStub } from '@tests/unit/shared/Stubs/ProcessEnvironmentStub';
|
||||
import { parseProjectInformation } from '@/application/Parser/ProjectInformationParser';
|
||||
import { IProjectInformation } from '@/domain/IProjectInformation';
|
||||
import { AppMetadataStub } from '@tests/unit/shared/Stubs/AppMetadataStub';
|
||||
|
||||
describe('ProjectInformationParser', () => {
|
||||
describe('parseProjectInformation', () => {
|
||||
interface IEnvironmentParsingTestCase {
|
||||
readonly testCaseName: string;
|
||||
readonly environmentVariableName: string;
|
||||
readonly environmentVariableValue: string;
|
||||
readonly setMetadata: (appMetadataStub: AppMetadataStub, value: string) => AppMetadataStub;
|
||||
readonly expectedValue: string;
|
||||
readonly getActualValue: (info: IProjectInformation) => string;
|
||||
}
|
||||
const testCases: readonly IEnvironmentParsingTestCase[] = [
|
||||
{
|
||||
testCaseName: 'version',
|
||||
environmentVariableName: VueAppEnvironmentKeys.VUE_APP_VERSION,
|
||||
environmentVariableValue: '0.11.3',
|
||||
setMetadata: (metadata, value) => metadata.withVersion(value),
|
||||
expectedValue: '0.11.3',
|
||||
getActualValue: (info) => info.version.toString(),
|
||||
},
|
||||
{
|
||||
testCaseName: 'name',
|
||||
environmentVariableName: VueAppEnvironmentKeys.VUE_APP_NAME,
|
||||
environmentVariableValue: 'expected-app-name',
|
||||
setMetadata: (metadata, value) => metadata.witName(value),
|
||||
expectedValue: 'expected-app-name',
|
||||
getActualValue: (info) => info.name,
|
||||
},
|
||||
{
|
||||
testCaseName: 'homepage',
|
||||
environmentVariableName: VueAppEnvironmentKeys.VUE_APP_HOMEPAGE_URL,
|
||||
environmentVariableValue: 'https://expected.sexy',
|
||||
setMetadata: (metadata, value) => metadata.withHomepageUrl(value),
|
||||
expectedValue: 'https://expected.sexy',
|
||||
getActualValue: (info) => info.homepage,
|
||||
},
|
||||
{
|
||||
testCaseName: 'repositoryUrl',
|
||||
environmentVariableName: VueAppEnvironmentKeys.VUE_APP_REPOSITORY_URL,
|
||||
environmentVariableValue: 'https://expected-repository.url',
|
||||
setMetadata: (metadata, value) => metadata.withRepositoryUrl(value),
|
||||
expectedValue: 'https://expected-repository.url',
|
||||
getActualValue: (info) => info.repositoryUrl,
|
||||
},
|
||||
{
|
||||
testCaseName: 'slogan',
|
||||
environmentVariableName: VueAppEnvironmentKeys.VUE_APP_SLOGAN,
|
||||
environmentVariableValue: 'expected-slogan',
|
||||
setMetadata: (metadata, value) => metadata.withSlogan(value),
|
||||
expectedValue: 'expected-slogan',
|
||||
getActualValue: (info) => info.slogan,
|
||||
},
|
||||
];
|
||||
for (const testCase of testCases) {
|
||||
it(`${testCase.testCaseName}`, () => {
|
||||
for (const {
|
||||
expectedValue, testCaseName, setMetadata, getActualValue,
|
||||
} of testCases) {
|
||||
it(testCaseName, () => {
|
||||
// act
|
||||
const expected = testCase.environmentVariableValue;
|
||||
const env = getProcessEnvironmentStub();
|
||||
env[testCase.environmentVariableName] = testCase.environmentVariableValue;
|
||||
const metadata = setMetadata(new AppMetadataStub(), expectedValue);
|
||||
// act
|
||||
const info = parseProjectInformation(env);
|
||||
const info = parseProjectInformation(metadata);
|
||||
// assert
|
||||
const actual = testCase.getActualValue(info);
|
||||
expect(actual).to.be.equal(expected);
|
||||
const actual = getActualValue(info);
|
||||
expect(actual).to.be.equal(expectedValue);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -4,11 +4,12 @@ import { OperatingSystem } from '@/domain/OperatingSystem';
|
||||
import { EnumRangeTestRunner } from '@tests/unit/application/Common/EnumRangeTestRunner';
|
||||
import { VersionStub } from '@tests/unit/shared/Stubs/VersionStub';
|
||||
import { Version } from '@/domain/Version';
|
||||
import { PropertyKeys } from '@tests/shared/TypeHelpers';
|
||||
|
||||
describe('ProjectInformation', () => {
|
||||
describe('retrieval of property values', () => {
|
||||
interface IPropertyTestCase {
|
||||
readonly testCaseName: string;
|
||||
interface IInformationParsingTestCase {
|
||||
readonly description?: string;
|
||||
readonly expectedValue: string;
|
||||
readonly buildWithExpectedValue: (
|
||||
builder: ProjectInformationBuilder,
|
||||
@@ -16,81 +17,105 @@ describe('ProjectInformation', () => {
|
||||
) => ProjectInformationBuilder;
|
||||
readonly getActualValue: (sut: ProjectInformation) => string;
|
||||
}
|
||||
const propertyTestCases: readonly IPropertyTestCase[] = [
|
||||
{
|
||||
testCaseName: 'name',
|
||||
expectedValue: 'expected-name',
|
||||
const propertyTestCases: {
|
||||
readonly [K in PropertyKeys<ProjectInformation>]: readonly IInformationParsingTestCase[];
|
||||
} = {
|
||||
name: [{
|
||||
expectedValue: 'expected-app-name',
|
||||
buildWithExpectedValue: (builder, expected) => builder
|
||||
.withName(expected),
|
||||
getActualValue: (sut) => sut.name,
|
||||
},
|
||||
{
|
||||
testCaseName: 'version',
|
||||
}],
|
||||
version: [{
|
||||
expectedValue: '0.11.3',
|
||||
buildWithExpectedValue: (builder, expected) => builder
|
||||
.withVersion(new VersionStub(expected)),
|
||||
getActualValue: (sut) => sut.version.toString(),
|
||||
},
|
||||
{
|
||||
testCaseName: 'repositoryWebUrl - not ending with .git',
|
||||
expectedValue: 'expected-repository-url',
|
||||
buildWithExpectedValue: (builder, expected) => builder
|
||||
.withRepositoryUrl(expected),
|
||||
getActualValue: (sut) => sut.repositoryWebUrl,
|
||||
},
|
||||
{
|
||||
testCaseName: 'repositoryWebUrl - ending with .git',
|
||||
expectedValue: 'expected-repository-url',
|
||||
buildWithExpectedValue: (builder, expected) => builder
|
||||
.withRepositoryUrl(`${expected}.git`),
|
||||
getActualValue: (sut) => sut.repositoryWebUrl,
|
||||
},
|
||||
{
|
||||
testCaseName: 'slogan',
|
||||
}],
|
||||
slogan: [{
|
||||
expectedValue: 'expected-slogan',
|
||||
buildWithExpectedValue: (builder, expected) => builder
|
||||
.withSlogan(expected),
|
||||
getActualValue: (sut) => sut.slogan,
|
||||
},
|
||||
{
|
||||
testCaseName: 'homepage',
|
||||
}],
|
||||
repositoryUrl: [{
|
||||
description: 'without `.git` suffix',
|
||||
expectedValue: 'expected-repository-url',
|
||||
buildWithExpectedValue: (builder, expected) => builder
|
||||
.withRepositoryUrl(expected),
|
||||
getActualValue: (sut) => sut.repositoryUrl,
|
||||
}, {
|
||||
description: 'with `.git` suffix',
|
||||
expectedValue: 'expected-repository-url',
|
||||
buildWithExpectedValue: (builder, expected) => builder
|
||||
.withRepositoryUrl(expected),
|
||||
getActualValue: (sut) => sut.repositoryUrl,
|
||||
}],
|
||||
repositoryWebUrl: [{
|
||||
description: 'without `.git` suffix',
|
||||
expectedValue: 'expected-repository-url',
|
||||
buildWithExpectedValue: (builder, expected) => builder
|
||||
.withRepositoryUrl(expected),
|
||||
getActualValue: (sut) => sut.repositoryWebUrl,
|
||||
}, {
|
||||
description: 'with `.git` suffix',
|
||||
expectedValue: 'expected-repository-url',
|
||||
buildWithExpectedValue: (builder, expected) => builder
|
||||
.withRepositoryUrl(`${expected}.git`),
|
||||
getActualValue: (sut) => sut.repositoryWebUrl,
|
||||
}],
|
||||
homepage: [{
|
||||
expectedValue: 'expected-homepage',
|
||||
buildWithExpectedValue: (builder, expected) => builder
|
||||
.withHomepage(expected),
|
||||
getActualValue: (sut) => sut.homepage,
|
||||
},
|
||||
{
|
||||
testCaseName: 'feedbackUrl',
|
||||
}],
|
||||
feedbackUrl: [{
|
||||
description: 'without `.git` suffix',
|
||||
expectedValue: 'https://github.com/undergroundwires/privacy.sexy/issues',
|
||||
buildWithExpectedValue: (builder) => builder
|
||||
.withRepositoryUrl('https://github.com/undergroundwires/privacy.sexy'),
|
||||
getActualValue: (sut) => sut.feedbackUrl,
|
||||
}, {
|
||||
description: 'with `.git` suffix',
|
||||
expectedValue: 'https://github.com/undergroundwires/privacy.sexy/issues',
|
||||
buildWithExpectedValue: (builder) => builder
|
||||
.withRepositoryUrl('https://github.com/undergroundwires/privacy.sexy.git'),
|
||||
getActualValue: (sut) => sut.feedbackUrl,
|
||||
},
|
||||
{
|
||||
testCaseName: 'releaseUrl',
|
||||
}],
|
||||
releaseUrl: [{
|
||||
description: 'without `.git` suffix',
|
||||
expectedValue: 'https://github.com/undergroundwires/privacy.sexy/releases/tag/0.7.2',
|
||||
buildWithExpectedValue: (builder) => builder
|
||||
.withRepositoryUrl('https://github.com/undergroundwires/privacy.sexy')
|
||||
.withVersion(new VersionStub('0.7.2')),
|
||||
getActualValue: (sut) => sut.releaseUrl,
|
||||
}, {
|
||||
description: 'with `.git` suffix',
|
||||
expectedValue: 'https://github.com/undergroundwires/privacy.sexy/releases/tag/0.7.2',
|
||||
buildWithExpectedValue: (builder) => builder
|
||||
.withRepositoryUrl('https://github.com/undergroundwires/privacy.sexy.git')
|
||||
.withVersion(new VersionStub('0.7.2')),
|
||||
getActualValue: (sut) => sut.releaseUrl,
|
||||
},
|
||||
];
|
||||
for (const testCase of propertyTestCases) {
|
||||
it(`should return the expected ${testCase.testCaseName} value`, () => {
|
||||
// arrange
|
||||
const expected = testCase.expectedValue;
|
||||
const builder = new ProjectInformationBuilder();
|
||||
const sut = testCase
|
||||
.buildWithExpectedValue(builder, expected)
|
||||
.build();
|
||||
}],
|
||||
};
|
||||
Object.entries(propertyTestCases).forEach(([propertyName, testList]) => {
|
||||
testList.forEach(({
|
||||
description, buildWithExpectedValue, expectedValue, getActualValue,
|
||||
}) => {
|
||||
it(`${propertyName}${description ? ` (${description})` : ''}`, () => {
|
||||
// arrange
|
||||
const builder = new ProjectInformationBuilder();
|
||||
const sut = buildWithExpectedValue(builder, expectedValue).build();
|
||||
|
||||
// act
|
||||
const actual = testCase.getActualValue(sut);
|
||||
// act
|
||||
const actual = getActualValue(sut);
|
||||
|
||||
// assert
|
||||
expect(actual).to.equal(expected);
|
||||
// assert
|
||||
expect(actual).to.equal(expectedValue);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
describe('correct retrieval of download URL per operating system', () => {
|
||||
const testCases: ReadonlyArray<{
|
||||
@@ -128,7 +153,7 @@ describe('ProjectInformation', () => {
|
||||
.withVersion(new VersionStub(version))
|
||||
.withRepositoryUrl(repositoryUrl)
|
||||
.build();
|
||||
// act
|
||||
// act
|
||||
const actual = sut.getDownloadUrl(os);
|
||||
// assert
|
||||
expect(actual).to.equal(expected);
|
||||
|
||||
65
tests/unit/infrastructure/Metadata/ViteAppMetadata.spec.ts
Normal file
65
tests/unit/infrastructure/Metadata/ViteAppMetadata.spec.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import {
|
||||
describe, beforeEach, afterEach, expect,
|
||||
} from 'vitest';
|
||||
import { ViteAppMetadata } from '@/infrastructure/Metadata/Vite/ViteAppMetadata';
|
||||
import { VITE_ENVIRONMENT_KEYS } from '@/infrastructure/Metadata/Vite/ViteEnvironmentKeys';
|
||||
import { PropertyKeys } from '@tests/shared/TypeHelpers';
|
||||
|
||||
describe('ViteAppMetadata', () => {
|
||||
describe('reads values from import.meta.env', () => {
|
||||
let originalMetaEnv;
|
||||
beforeEach(() => {
|
||||
originalMetaEnv = { ...import.meta.env };
|
||||
});
|
||||
afterEach(() => {
|
||||
Object.assign(import.meta.env, originalMetaEnv);
|
||||
});
|
||||
|
||||
interface ITestCase {
|
||||
readonly getActualValue: (sut: ViteAppMetadata) => string;
|
||||
readonly environmentVariable: typeof VITE_ENVIRONMENT_KEYS[
|
||||
keyof typeof VITE_ENVIRONMENT_KEYS];
|
||||
readonly expected: string;
|
||||
}
|
||||
const testCases: { [K in PropertyKeys<ViteAppMetadata>]: ITestCase } = {
|
||||
name: {
|
||||
environmentVariable: VITE_ENVIRONMENT_KEYS.NAME,
|
||||
expected: 'expected-name',
|
||||
getActualValue: (sut) => sut.name,
|
||||
},
|
||||
version: {
|
||||
environmentVariable: VITE_ENVIRONMENT_KEYS.VERSION,
|
||||
expected: 'expected-version',
|
||||
getActualValue: (sut) => sut.version,
|
||||
},
|
||||
repositoryUrl: {
|
||||
environmentVariable: VITE_ENVIRONMENT_KEYS.REPOSITORY_URL,
|
||||
expected: 'expected-slogan',
|
||||
getActualValue: (sut) => sut.repositoryUrl,
|
||||
},
|
||||
slogan: {
|
||||
environmentVariable: VITE_ENVIRONMENT_KEYS.SLOGAN,
|
||||
expected: 'expected-repositoryUrl',
|
||||
getActualValue: (sut) => sut.slogan,
|
||||
},
|
||||
homepageUrl: {
|
||||
environmentVariable: VITE_ENVIRONMENT_KEYS.HOMEPAGE_URL,
|
||||
expected: 'expected-homepageUrl',
|
||||
getActualValue: (sut) => sut.homepageUrl,
|
||||
},
|
||||
};
|
||||
Object.values(testCases).forEach(({ environmentVariable, expected, getActualValue }) => {
|
||||
it(`should correctly get the value of ${environmentVariable}`, () => {
|
||||
// arrange
|
||||
import.meta.env[environmentVariable] = expected;
|
||||
|
||||
// act
|
||||
const sut = new ViteAppMetadata();
|
||||
const actualValue = getActualValue(sut);
|
||||
|
||||
// assert
|
||||
expect(actualValue).toBe(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
import { expect, describe, it } from 'vitest';
|
||||
import { VITE_ENVIRONMENT_KEYS } from '@/infrastructure/Metadata/Vite/ViteEnvironmentKeys';
|
||||
|
||||
describe('VITE_ENVIRONMENT_KEYS', () => {
|
||||
describe('each key should have a non-empty string', () => {
|
||||
Object.entries(VITE_ENVIRONMENT_KEYS).forEach(([key, value]) => {
|
||||
it(`The key ${key} should have a non-empty string value`, () => {
|
||||
expect(typeof value).toBe('string');
|
||||
expect(value.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
38
tests/unit/shared/Stubs/AppMetadataStub.ts
Normal file
38
tests/unit/shared/Stubs/AppMetadataStub.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { IAppMetadata } from '@/infrastructure/Metadata/IAppMetadata';
|
||||
|
||||
export class AppMetadataStub implements IAppMetadata {
|
||||
public version = '0.12.2';
|
||||
|
||||
public name = 'stub-name';
|
||||
|
||||
public slogan = 'stub-slogan';
|
||||
|
||||
public repositoryUrl = 'stub-repository-url';
|
||||
|
||||
public homepageUrl = 'stub-homepage-url';
|
||||
|
||||
public withVersion(version: string): this {
|
||||
this.version = version;
|
||||
return this;
|
||||
}
|
||||
|
||||
public witName(name: string): this {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public withSlogan(slogan: string): this {
|
||||
this.slogan = slogan;
|
||||
return this;
|
||||
}
|
||||
|
||||
public withRepositoryUrl(repositoryUrl: string): this {
|
||||
this.repositoryUrl = repositoryUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
public withHomepageUrl(homepageUrl: string): this {
|
||||
this.homepageUrl = homepageUrl;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { expect } from 'vitest';
|
||||
import { Constructible } from '@tests/shared/TypeHelpers';
|
||||
import { ICodeValidationRule } from '@/application/Parser/Script/Validation/ICodeValidationRule';
|
||||
import { ICodeValidator } from '@/application/Parser/Script/Validation/ICodeValidator';
|
||||
import { Type } from '../Type';
|
||||
|
||||
export class CodeValidatorStub implements ICodeValidator {
|
||||
public callHistory = new Array<{
|
||||
@@ -21,7 +21,7 @@ export class CodeValidatorStub implements ICodeValidator {
|
||||
|
||||
public assertHistory(expected: {
|
||||
validatedCodes: readonly string[],
|
||||
rules: readonly Type<ICodeValidationRule>[],
|
||||
rules: readonly Constructible<ICodeValidationRule>[],
|
||||
}) {
|
||||
expect(this.callHistory).to.have.lengthOf(expected.validatedCodes.length);
|
||||
const actualValidatedCodes = this.callHistory.map((args) => args.code);
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import { VueAppEnvironment } from '@/application/Parser/ProjectInformationParser';
|
||||
|
||||
export function getProcessEnvironmentStub(): VueAppEnvironment {
|
||||
return {
|
||||
VUE_APP_VERSION: '0.11.3',
|
||||
VUE_APP_NAME: 'stub-name',
|
||||
VUE_APP_SLOGAN: 'stub-slogan',
|
||||
VUE_APP_REPOSITORY_URL: 'stub-repository-url',
|
||||
VUE_APP_HOMEPAGE_URL: 'stub-homepage-url',
|
||||
};
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
import { it, expect } from 'vitest';
|
||||
import { Type } from '../Type';
|
||||
import { Constructible } from '@tests/shared/TypeHelpers';
|
||||
|
||||
interface ISingletonTestData<T> {
|
||||
getter: () => T;
|
||||
expectedType: Type<T>;
|
||||
expectedType: Constructible<T>;
|
||||
}
|
||||
|
||||
export function itIsSingleton<T>(test: ISingletonTestData<T>): void {
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
export type Type<T, TArgs extends unknown[] = never> = Function & {
|
||||
prototype: T,
|
||||
apply: (this: unknown, args: TArgs) => void
|
||||
};
|
||||
Reference in New Issue
Block a user