Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libs/components/i18n/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"save": "dependencies"
},
"peerDependencies": {
"@angular/cdk": "^20.2.3",
"@angular/cli": "^20.3.1",
"@angular/common": "^20.3.0",
"@angular/core": "^20.3.0",
Expand Down
14 changes: 11 additions & 3 deletions libs/components/i18n/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"projectType": "library",
"sourceRoot": "libs/components/i18n/src",
"prefix": "sky",
"tags": ["component", "npm"],
"targets": {
"build": {
"executor": "@nx/angular:package",
Expand All @@ -19,7 +20,15 @@
"tsConfig": "libs/components/i18n/tsconfig.lib.json"
}
},
"defaultConfiguration": "production"
"defaultConfiguration": "production",
"dependsOn": ["^build"],
"inputs": [
"buildInputs",
"^buildInputs",
"{workspaceRoot}/libs/components/i18n/testing/src/**/*",
"!{workspaceRoot}/libs/components/i18n/testing/src/**/*.spec.ts",
"!{workspaceRoot}/libs/components/i18n/testing/src/**/fixtures/**/*"
]
},
"test": {
"executor": "@angular-devkit/build-angular:karma",
Expand Down Expand Up @@ -74,6 +83,5 @@
"command": "ts-node --project ./scripts/tsconfig.json ./scripts/posttest-i18n.ts"
}
}
},
"tags": ["component", "npm"]
}
}
5 changes: 5 additions & 0 deletions libs/components/i18n/testing/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const prettier = require('eslint-config-prettier');
const baseConfig = require('../../../../eslint-base.config');
const overrides = require('../../../../eslint-overrides.config');

module.exports = [...baseConfig, ...overrides, prettier];
16 changes: 16 additions & 0 deletions libs/components/i18n/testing/karma.conf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html

const { join } = require('path');
const getBaseKarmaConfig = require('../../../../karma.conf');

module.exports = function (config) {
const baseConfig = getBaseKarmaConfig();
config.set({
...baseConfig,
coverageReporter: {
...baseConfig.coverageReporter,
dir: join(__dirname, '../../../../coverage/libs/components/i18n/testing'),
},
});
};
5 changes: 5 additions & 0 deletions libs/components/i18n/testing/ng-package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"lib": {
"entryFile": "src/public-api.ts"
}
}
47 changes: 47 additions & 0 deletions libs/components/i18n/testing/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"name": "i18n-testing",
"$schema": "../../../../node_modules/nx/schemas/project-schema.json",
"projectType": "library",
"sourceRoot": "libs/components/i18n/testing/src",
"prefix": "sky",
"tags": ["testing"],
"targets": {
"test": {
"executor": "@angular-devkit/build-angular:karma",
"options": {
"tsConfig": "libs/components/i18n/testing/tsconfig.spec.json",
"karmaConfig": "libs/components/i18n/testing/karma.conf.js",
"codeCoverage": true,
"codeCoverageExclude": ["**/fixtures/**"],
"styles": [
"libs/components/theme/src/lib/styles/sky.scss",
"libs/components/theme/src/lib/styles/themes/modern/styles.scss"
],
"polyfills": [
"zone.js",
"zone.js/testing",
"libs/components/packages/src/polyfills.js"
],
"inlineStyleLanguage": "scss",
"stylePreprocessorOptions": {
"includePaths": ["{workspaceRoot}"]
}
},
"configurations": {
"ci": {
"browsers": "ChromeHeadlessNoSandbox",
"codeCoverage": true,
"progress": false,
"sourceMap": true,
"watch": false
}
}
},
"lint": {
"executor": "@nx/eslint:lint",
"options": {
"lintFilePatterns": ["{projectRoot}/src/**/*.ts"]
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { BaseHarnessFilters } from '@angular/cdk/testing';

/**
* A set of criteria that can be used to filter a list of `SkyResourcesHarness` instances.
*/
export interface SkyResourcesHarnessFilters extends BaseHarnessFilters {
/**
* Only find instances whose `data-sky-id` attribute matches the given value.
*/
dataSkyId?: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import { HarnessLoader } from '@angular/cdk/testing';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { Component } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { SkyI18nModule, SkyLibResourcesService } from '@skyux/i18n';

import { SkyResourcesHarness } from './resources-harness';

@Component({
selector: 'sky-resources-test',
template: `
<span data-sky-id="test-resources" skyLibResources>{{ resourceText }}</span>
<span
data-sky-id="test-resources-with-attr"
skyLibResources
[title]="titleText"
>{{ resourceText }}</span
>
`,
standalone: false,
})
class TestComponent {
public resourceText = 'Hello World';
public titleText = 'Test Title';
}

describe('Resources harness', () => {
async function setupTest(options: { dataSkyId?: string } = {}): Promise<{
harness: SkyResourcesHarness;
fixture: ComponentFixture<TestComponent>;
loader: HarnessLoader;
}> {
await TestBed.configureTestingModule({
declarations: [TestComponent],
imports: [SkyI18nModule],
providers: [SkyLibResourcesService],
}).compileComponents();

const fixture = TestBed.createComponent(TestComponent);
const loader = TestbedHarnessEnvironment.loader(fixture);

let harness: SkyResourcesHarness;

if (options.dataSkyId) {
harness = await loader.getHarness(
SkyResourcesHarness.with({
dataSkyId: options.dataSkyId,
}),
);
} else {
harness = await loader.getHarness(SkyResourcesHarness);
}

return { harness, fixture, loader };
}

it('should get the text content of the element', async () => {
const { harness, fixture } = await setupTest({
dataSkyId: 'test-resources',
});

fixture.detectChanges();

await expectAsync(harness.getText()).toBeResolvedTo('Hello World');
});

it('should get updated text content when resource text changes', async () => {
const { harness, fixture } = await setupTest({
dataSkyId: 'test-resources',
});

fixture.detectChanges();

await expectAsync(harness.getText()).toBeResolvedTo('Hello World');

fixture.componentInstance.resourceText = 'Updated Text';
fixture.detectChanges();

await expectAsync(harness.getText()).toBeResolvedTo('Updated Text');
});

it('should get the inner HTML of the element', async () => {
const { harness, fixture } = await setupTest({
dataSkyId: 'test-resources',
});

fixture.detectChanges();

const innerHTML = await harness.getInnerHtml();
expect(innerHTML).toContain('Hello World');
});

it('should get an attribute value from the element', async () => {
const { harness, fixture } = await setupTest({
dataSkyId: 'test-resources-with-attr',
});

fixture.detectChanges();

await expectAsync(harness.getAttribute('title')).toBeResolvedTo(
'Test Title',
);
});

it('should return null for non-existent attribute', async () => {
const { harness, fixture } = await setupTest({
dataSkyId: 'test-resources',
});

fixture.detectChanges();

await expectAsync(harness.getAttribute('non-existent-attr')).toBeResolvedTo(
null,
);
});

it('should find harness without dataSkyId filter', async () => {
const { harness, fixture } = await setupTest();

fixture.detectChanges();

await expectAsync(harness.getText()).toBeResolvedTo('Hello World');
});

it('should get all harnesses matching the selector', async () => {
const { loader, fixture } = await setupTest();

fixture.detectChanges();

const harnesses = await loader.getAllHarnesses(SkyResourcesHarness);

expect(harnesses.length).toBe(2);
});
});
58 changes: 58 additions & 0 deletions libs/components/i18n/testing/src/modules/i18n/resources-harness.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';

import { SkyResourcesHarnessFilters } from './resources-harness-filters';

/**
* Harness for interacting with elements that display localized resource strings in tests.
* This harness can be used to verify that components correctly display localized content.
*/
export class SkyResourcesHarness extends ComponentHarness {
/**
* @internal
*/
public static hostSelector = '[skyLibResources],[skyAppResources]';

/**
* Gets a `HarnessPredicate` that can be used to search for a
* `SkyResourcesHarness` that meets certain criteria.
*/
public static with(
filters: SkyResourcesHarnessFilters,
): HarnessPredicate<SkyResourcesHarness> {
return new HarnessPredicate(SkyResourcesHarness, filters).addOption(
'dataSkyId',
filters.dataSkyId,
(harness, text) =>
HarnessPredicate.stringMatches(harness.#getSkyId(), text),
);
}

async #getSkyId(): Promise<string | null> {
return await (await this.host()).getAttribute('data-sky-id');
}

/**
* Gets the text content of the element.
*/
public async getText(): Promise<string> {
const host = await this.host();
return (await host.text()).trim();
}

/**
* Gets the inner HTML of the element.
*/
public async getInnerHtml(): Promise<string> {
const host = await this.host();
return await host.getProperty<string>('innerHTML');
}

/**
* Gets the value of a specific attribute on the element.
* @param name The name of the attribute.
*/
public async getAttribute(name: string): Promise<string | null> {
const host = await this.host();
return await host.getAttribute(name);
}
}
2 changes: 2 additions & 0 deletions libs/components/i18n/testing/src/public-api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { SkyResourcesHarness } from './modules/i18n/resources-harness';
export { SkyResourcesHarnessFilters } from './modules/i18n/resources-harness-filters';
8 changes: 8 additions & 0 deletions libs/components/i18n/testing/tsconfig.spec.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "../tsconfig.spec.json",
"compilerOptions": {
"outDir": "../../../../out-tsc/spec",
"types": ["jasmine", "node"]
},
"include": ["**/*.spec.ts", "**/*.d.ts"]
}
1 change: 1 addition & 0 deletions libs/components/theme/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
},
"homepage": "https://github.com/blackbaud/skyux#readme",
"peerDependencies": {
"@angular/cdk": "^20.2.3",
"@angular/common": "^20.3.0",
"@angular/core": "^20.3.0"
},
Expand Down
14 changes: 11 additions & 3 deletions libs/components/theme/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"projectType": "library",
"sourceRoot": "libs/components/theme/src",
"prefix": "sky",
"tags": ["component", "npm"],
"targets": {
"build": {
"executor": "@nx/angular:package",
Expand All @@ -19,7 +20,15 @@
"tsConfig": "libs/components/theme/tsconfig.lib.json"
}
},
"defaultConfiguration": "production"
"defaultConfiguration": "production",
"dependsOn": ["^build"],
"inputs": [
"buildInputs",
"^buildInputs",
"{workspaceRoot}/libs/components/theme/testing/src/**/*",
"!{workspaceRoot}/libs/components/theme/testing/src/**/*.spec.ts",
"!{workspaceRoot}/libs/components/theme/testing/src/**/fixtures/**/*"
]
},
"test": {
"executor": "@angular-devkit/build-angular:karma",
Expand Down Expand Up @@ -67,6 +76,5 @@
"command": "ts-node --project ./scripts/tsconfig.json ./scripts/postbuild-theme.ts"
}
}
},
"tags": ["component", "npm"]
}
}
5 changes: 5 additions & 0 deletions libs/components/theme/testing/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const prettier = require('eslint-config-prettier');
const baseConfig = require('../../../../eslint-base.config');
const overrides = require('../../../../eslint-overrides.config');

module.exports = [...baseConfig, ...overrides, prettier];
Loading
Loading