Skip to content

Commit

Permalink
test: wait for SVG icon sprite when loading fonts (#3158)
Browse files Browse the repository at this point in the history
  • Loading branch information
Blackbaud-PaulCrowder authored Feb 14, 2025
1 parent ac3da23 commit 000ebf4
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ describe('popovers-storybook', () => {
cy.visit(
`/iframe.html?globals=theme:${theme}&id=dropdowncomponent-dropdown--dropdown-${buttonStyle}-button`,
);
cy.get('#ready').should('exist');
cy.get('app-dropdown')
.should('exist')
.should('be.visible')
Expand All @@ -33,6 +34,7 @@ describe('popovers-storybook', () => {

['select', 'context-menu', 'tab', 'custom'].forEach((buttonType) => {
it(`should open the ${buttonType} style dropdown's menu`, () => {
cy.get('#ready').should('exist');
cy.get('app-dropdown').should('exist').should('be.visible');
cy.get(
buttonType === 'custom'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,7 @@
<sky-dropdown-item>Item 3</sky-dropdown-item>
</sky-dropdown-menu>
</sky-dropdown>

@if (ready()) {
<span id="ready"></span>
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { Component, Input } from '@angular/core';
import { Component, Input, inject } from '@angular/core';
import { toSignal } from '@angular/core/rxjs-interop';
import { FontLoadingService } from '@skyux/storybook/font-loading';

@Component({
selector: 'app-dropdown',
Expand All @@ -14,4 +16,6 @@ export class DropdownComponent {

@Input()
public disabledFlag = false;

protected ready = toSignal(inject(FontLoadingService).ready(true));
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
import { TestBed } from '@angular/core/testing';

import FontFaceObserver from 'fontfaceobserver';
import { firstValueFrom } from 'rxjs';
import { map } from 'rxjs/operators';

import { FontLoadingService } from './font-loading.service';

describe('FontLoadingService', () => {
let service: FontLoadingService;

function createSvgSprite(): void {
const svgEl = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svgEl.id = 'sky-icon-svg-sprite';

document.body.appendChild(svgEl);
}

beforeEach(() => {
spyOn(FontFaceObserver.prototype, 'load').and.callFake(() =>
Promise.resolve(),
Expand All @@ -16,6 +24,10 @@ describe('FontLoadingService', () => {
service = TestBed.inject(FontLoadingService);
});

afterEach(() => {
document.getElementById('sky-icon-svg-sprite')?.remove();
});

it('should be created', () => {
expect(service).toBeTruthy();
});
Expand All @@ -30,4 +42,22 @@ describe('FontLoadingService', () => {
)
.toPromise();
});

describe('when waiting for SVG icons', () => {
it('should resolve when the SVG sprite appears in the DOM before calling ready()', async () => {
createSvgSprite();

const readyPromise = service.ready(true);

await expectAsync(firstValueFrom(readyPromise)).toBeResolvedTo(true);
});

it('should resolve when the SVG sprite appears in the DOM after calling ready()', async () => {
const readyPromise = service.ready(true);

createSvgSprite();

await expectAsync(firstValueFrom(readyPromise)).toBeResolvedTo(true);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,38 @@ import FontFaceObserver from 'fontfaceobserver';
import { Observable, from } from 'rxjs';
import { map } from 'rxjs/operators';

const SPRITE_ID = 'sky-icon-svg-sprite';

async function waitForSvgSprite(): Promise<void> {
return await new Promise<void>((resolve) => {
if (document.getElementById(SPRITE_ID)) {
resolve();
} else {
const observer = new MutationObserver((mutations) => {
if (
mutations.some((mutation) =>
Array.from(mutation.addedNodes).some(
(node) => (node as Element).id === SPRITE_ID,
),
)
) {
observer.disconnect();
resolve();
}
});

observer.observe(document.body, {
childList: true,
});
}
});
}

@Injectable({
providedIn: 'root',
})
export class FontLoadingService {
public ready(): Observable<boolean> {
public ready(waitForSvgIcons?: boolean): Observable<boolean> {
const fonts: FontFaceObserver[] = [
design.text.weight.light,
design.text.weight.regular,
Expand All @@ -36,8 +63,12 @@ export class FontLoadingService {
}),
);

return from(Promise.all(fonts.map((font) => font.load()))).pipe(
map(() => true),
);
const fontPromises = fonts.map((font) => font.load());

if (waitForSvgIcons) {
fontPromises.push(waitForSvgSprite());
}

return from(Promise.all(fontPromises)).pipe(map(() => true));
}
}

0 comments on commit 000ebf4

Please sign in to comment.