genesys-spark 4.0.0-beta.64 → 4.0.0-beta.65

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -241,7 +241,7 @@ var intl = /*#__PURE__*/Object.freeze({
241
241
  relativeTimeFormat: relativeTimeFormat
242
242
  });
243
243
 
244
- var ASSET_PREFIX = '/spark-components/build-assets/4.0.0-beta.64-1/genesys-webcomponents/';
244
+ var ASSET_PREFIX = '/spark-components/build-assets/4.0.0-beta.65-3/genesys-webcomponents/';
245
245
  var SCRIPT_PATH = 'genesys-webcomponents.esm.js';
246
246
  var STYLE_PATH = 'genesys-webcomponents.css';
247
247
  var assetsOrigin = getAssetsOrigin();
package/package.json CHANGED
@@ -1,11 +1,14 @@
1
1
  {
2
2
  "name": "genesys-spark",
3
- "version": "4.0.0-beta.64",
3
+ "version": "4.0.0-beta.65",
4
4
  "description": "",
5
5
  "license": "ISC",
6
6
  "author": "",
7
7
  "type": "module",
8
8
  "main": "dist/index.js",
9
+ "files": [
10
+ "dist/src/*.d.ts"
11
+ ],
9
12
  "scripts": {
10
13
  "build": "rollup -c",
11
14
  "dev": "rollup -c --watch",
@@ -16,6 +19,7 @@
16
19
  "test.watch": "jest --watch",
17
20
  "version-sync": "npm version --no-git-tag-version --allow-same-version"
18
21
  },
22
+ "types": "dist/src/index.d.ts",
19
23
  "dependencies": {
20
24
  "@rollup/plugin-replace": "^5.0.5",
21
25
  "@rollup/plugin-typescript": "^11.1.5",
package/.eslintignore DELETED
@@ -1,5 +0,0 @@
1
- node_modules/
2
- dist/
3
- rollup.config.js
4
- jest.config.js
5
-
package/.eslintrc.json DELETED
@@ -1,34 +0,0 @@
1
- {
2
- "parser": "@typescript-eslint/parser",
3
- "plugins": ["@typescript-eslint"],
4
- "root": true,
5
- "env": {
6
- "browser": true,
7
- "es6": true
8
- },
9
- "rules": {
10
- "no-unused-vars": "off",
11
- "no-undef": "off"
12
- },
13
- "extends": ["genesys-spark-components"],
14
- "parserOptions": {
15
- "sourceType": "module",
16
- "project": ["./tsconfig.json"]
17
- },
18
- "overrides": [
19
- {
20
- "files": ["./test/**/*.ts"],
21
- "env": {
22
- "node": true,
23
- "es6": true,
24
- "jest": true
25
- },
26
- "extends": ["genesys-spark-components/typescript"],
27
- "rules": {
28
- "@typescript-eslint/no-unsafe-assignment": "off",
29
- "@typescript-eslint/ban-ts-comment": "off",
30
- "@typescript-eslint/no-explicit-any": "off"
31
- }
32
- }
33
- ]
34
- }
@@ -1,6 +0,0 @@
1
- {
2
- "*": "prettier --ignore-unknown --write",
3
- "*.{css,html,scss}": "stylelint --fix",
4
- "*.{ts,tsx,js,jsx}": "eslint --fix ",
5
- "package.json": ["prettier-package-json --write"]
6
- }
package/.prettierignore DELETED
@@ -1,2 +0,0 @@
1
- node_modules/
2
- dist/
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
package/jest.config.js DELETED
@@ -1,5 +0,0 @@
1
- /** @type {import('ts-jest').JestConfigWithTsJest} */
2
- export default {
3
- preset: 'ts-jest',
4
- testEnvironment: 'jsdom'
5
- };
package/rollup.config.js DELETED
@@ -1,23 +0,0 @@
1
- import replace from '@rollup/plugin-replace';
2
- import typescript from '@rollup/plugin-typescript';
3
-
4
- const IS_DEV_MODE = process.env.ROLLUP_WATCH === 'true';
5
-
6
- export default {
7
- input: 'src/index.ts',
8
- output: {
9
- dir: 'dist'
10
- },
11
- plugins: [
12
- replace({
13
- values: {
14
- IS_DEV_MODE: IS_DEV_MODE,
15
- __ASSET_PREFIX__: IS_DEV_MODE
16
- ? '/dist/genesys-webcomponents/'
17
- : process.env.COMPONENT_ASSETS_PATH
18
- },
19
- preventAssignment: true
20
- }),
21
- typescript({ noEmitOnError: false })
22
- ]
23
- };
package/src/hosts.ts DELETED
@@ -1,57 +0,0 @@
1
- declare global {
2
- // IS_DEV_MODE is rewritten by @rollup/plugin-replace. This definition lets
3
- // our typescript file typecheck.
4
- var IS_DEV_MODE: boolean;
5
- }
6
-
7
- // Default domain to load assets from
8
- const DEFAULT_DOMAIN = 'mypurecloud.com';
9
-
10
- // List of Genesys UI domains that do not follow the ${region}.pure.cloud format
11
- const NON_STANDARD_DOMAINS = [
12
- 'inindca.com',
13
- 'inintca.com',
14
- 'mypurecloud.com.au',
15
- 'mypurecloud.com',
16
- 'mypurecloud.de',
17
- 'mypurecloud.ie',
18
- 'mypurecloud.jp'
19
- // 'use2.us-gov-pure.cloud', Assets are not currently deployed to FedRAMP. It should fall back to the default domain.
20
- ];
21
-
22
- /**
23
- * Returns the origin that web component assets should be loaded from.
24
- * Will use the domain of the current window if it matches a Genesys domain.
25
- */
26
- export function getAssetsOrigin(): string {
27
- if (IS_DEV_MODE == true) {
28
- // This conditional is optimized out in production due to @rollup/plugin-replace
29
- // and rollup's dead code elimination
30
- return 'http://localhost:3333';
31
- }
32
-
33
- const matchedDomain = getRegionDomain();
34
- return `https://app.${matchedDomain || DEFAULT_DOMAIN}`;
35
- }
36
-
37
- export function getFontOrigin(): string {
38
- if (IS_DEV_MODE == true) {
39
- // Fonts aren't locally hosted during dev mode
40
- return 'http://app.inindca.com';
41
- }
42
- return getAssetsOrigin();
43
- }
44
-
45
- function getRegionDomain() {
46
- const pageHost = window.location.hostname;
47
-
48
- // We can automatically handle the standard domain format: ${region}.pure.cloud
49
- if (pageHost.endsWith('.pure.cloud')) {
50
- return pageHost.split('.').slice(-3).join('.');
51
- }
52
-
53
- // For older domains, we have to do a lookup
54
- return NON_STANDARD_DOMAINS.find(regionDomain =>
55
- pageHost.endsWith(regionDomain)
56
- );
57
- }
package/src/index.ts DELETED
@@ -1,39 +0,0 @@
1
- import { getAssetsOrigin, getFontOrigin } from './hosts';
2
- import {
3
- checkAndLoadScript,
4
- checkAndLoadStyle,
5
- checkAndLoadFonts
6
- } from './loading';
7
-
8
- const ASSET_PREFIX = '__ASSET_PREFIX__';
9
- const SCRIPT_PATH = 'genesys-webcomponents.esm.js';
10
- const STYLE_PATH = 'genesys-webcomponents.css';
11
-
12
- const assetsOrigin = getAssetsOrigin();
13
- const SCRIPT_SRC = `${assetsOrigin}${ASSET_PREFIX}${SCRIPT_PATH}`;
14
- const STYLE_HREF = `${assetsOrigin}${ASSET_PREFIX}${STYLE_PATH}`;
15
- const fontOrigin = getFontOrigin();
16
- const FONTS = {
17
- Urbanist: `${fontOrigin}/webfonts/urbanist.css`,
18
- 'Noto Sans': `${fontOrigin}/webfonts/noto-sans.css`
19
- };
20
-
21
- /**
22
- * Loads the spark web components, as well as required CSS and fonts from a
23
- * shared CDN. Performance can be optimized by pre-loading fonts in static HTML.
24
- *
25
- * @returns a promise that succeeds if the component script and styles
26
- * load successfully. It is not recommended to wait on this promise or to stop
27
- * application bootstrap if it rejects. Its primary use should be for logging
28
- * unexpected failures.
29
- */
30
- export function registerSparkComponents(): Promise<void> {
31
- return Promise.all([
32
- checkAndLoadScript(SCRIPT_SRC),
33
- checkAndLoadStyle(STYLE_HREF),
34
- checkAndLoadFonts(FONTS)
35
- ]).then();
36
- }
37
-
38
- // Re-export of utility modules
39
- export * as Intl from './intl';
package/src/intl.ts DELETED
@@ -1,88 +0,0 @@
1
- /**
2
- * Provides an [Intl.DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat)
3
- * object for formatting dates and times. Unlike the native version, `locale` is
4
- * an optional argument. If not provided, the function will try to determine the
5
- * locale from the DOM, where it should be set for a11y reasons.
6
- * @param locale optional locale to use for formatting
7
- * @param options options to pass to the Intl.DateTimeFormat constructor
8
- * @returns a new DateTimeFormat
9
- */
10
- export function dateTimeFormat(
11
- localeOrOptions: string | Intl.DateTimeFormatOptions,
12
- options?: Intl.DateTimeFormatOptions
13
- ): Intl.DateTimeFormat {
14
- let locale = undefined;
15
- if (typeof localeOrOptions === 'string') {
16
- locale = localeOrOptions;
17
- } else {
18
- options = localeOrOptions;
19
- }
20
-
21
- if (locale != undefined) {
22
- return new Intl.DateTimeFormat(locale, options);
23
- } else {
24
- const userLocale = determineDisplayLocale();
25
- return new Intl.DateTimeFormat(userLocale, options);
26
- }
27
- }
28
- /**
29
- * Provides an [Intl.RelativeTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat)
30
- * object for formatting dates and times. Unlike the native version, `locale` is
31
- * an optional argument. If not provided, the function will try to determine the
32
- * locale from the DOM, where it should be set for a11y reasons.
33
- * @param locale optional locale to use for formatting
34
- * @param options options to pass to the Intl.RelativeTimeFormat constructor
35
- * @returns a new RelativeTimeFormat
36
- */
37
- export function relativeTimeFormat(
38
- localeOrOptions: string | Intl.RelativeTimeFormatOptions,
39
- options?: Intl.RelativeTimeFormatOptions
40
- ): Intl.RelativeTimeFormat {
41
- let locale = undefined;
42
- if (typeof localeOrOptions === 'string') {
43
- locale = localeOrOptions;
44
- } else {
45
- options = localeOrOptions;
46
- }
47
-
48
- if (locale != undefined) {
49
- return new Intl.RelativeTimeFormat(locale, options);
50
- } else {
51
- const userLocale = determineDisplayLocale();
52
- return new Intl.RelativeTimeFormat(userLocale, options);
53
- }
54
- }
55
-
56
- /**
57
- * Makes a best effort to return the locale that should be used for a given element
58
- * by checking language tags on ancestors. If no element is provided, it will
59
- * start with the document's <body> tag. If no locale can be found, it will use
60
- * the browser's locale preference. It will also try to add a region to regionless
61
- * locales when there is a partial match with the browser's locale.
62
- * @returns a locale string (e.g. 'en-US', 'en', 'de-DE', etc)
63
- */
64
- export function determineDisplayLocale(
65
- element: HTMLElement = document.body
66
- ): string {
67
- const domLocale = element.closest<HTMLElement>('[lang]')?.lang;
68
- if (!domLocale || browserHasRegionData(domLocale)) {
69
- // If we can't find a locale in the DOM, or we find a locale without a region that matches the
70
- // users's browser locale, use the browser locale.
71
- return navigator.language;
72
- } else {
73
- return domLocale;
74
- }
75
- }
76
-
77
- /**
78
- * Returns true if the provided locale only has a language, but the user's
79
- * browser settings have the same language with a locale.
80
- * @param localeString The locale to check
81
- * @returns true if the region can be guessed from the browser settings.
82
- */
83
- function browserHasRegionData(localeString: string): boolean {
84
- return (
85
- localeString.length == 2 &&
86
- navigator.language.startsWith(`${localeString}-`)
87
- );
88
- }
package/src/loading.ts DELETED
@@ -1,90 +0,0 @@
1
- /**
2
- * Add a script tag to the document if it is not already present.
3
- * @param scriptSrc The src attribute of the script
4
- * @returns a promise that resolves if the script loads or is already present
5
- */
6
- export function checkAndLoadScript(scriptSrc: string): Promise<void> {
7
- const existingTag = document.querySelector(`script[src="${scriptSrc}"]`);
8
- if (existingTag) {
9
- return Promise.resolve();
10
- } else {
11
- const scriptTag = document.createElement('script');
12
- scriptTag.setAttribute('type', 'module');
13
- scriptTag.setAttribute('src', scriptSrc);
14
- const result = new Promise<void>((resolve, reject) => {
15
- scriptTag.addEventListener('load', () => {
16
- resolve();
17
- });
18
- scriptTag.addEventListener('error', () => {
19
- reject(`Spark script failed to load: ${scriptSrc}`);
20
- });
21
- });
22
- document.head.appendChild(scriptTag);
23
- return result;
24
- }
25
- }
26
-
27
- /**
28
- * Add a stylesheet link tag to the document if it is not already present.
29
- * @param styleHref The href attribute of the stylesheet
30
- * @returns a promise that resolves if the style loads or is already present
31
- */
32
- export function checkAndLoadStyle(styleHref: string): Promise<void> {
33
- const existingTag = document.querySelector(`link[href="${styleHref}"]`);
34
- if (existingTag) {
35
- return Promise.resolve();
36
- } else {
37
- const styleTag = document.createElement('link');
38
- styleTag.setAttribute('href', styleHref);
39
- styleTag.setAttribute('rel', 'stylesheet');
40
- const result = new Promise<void>((resolve, reject) => {
41
- styleTag.addEventListener('load', () => {
42
- resolve();
43
- });
44
- styleTag.addEventListener('error', () => {
45
- reject(`Spark styles failed to load: ${styleHref}`);
46
- });
47
- });
48
- document.head.appendChild(styleTag);
49
- return result;
50
- }
51
- }
52
-
53
- /**
54
- * Given an object that maps font-family identifiers to CSS urls e.g:
55
- * {
56
- * "Urbanist": "/urbanist.css",
57
- * "Noto Sans": "/noto-sans.css"
58
- * }
59
- * This function checks for loaded fonts with those identifiers. If a font is
60
- * not found, the corresponding stylesheet is added to the document.
61
- * @param fonts An object mapping font-family identifiers to CSS file urls
62
- * @returns A promise that resolves once the script tags has finished loading.
63
- * It does not fail if the script tags fail to load because we don't want to fail
64
- * the whole component loading process in that situation.
65
- */
66
- export function checkAndLoadFonts(fonts: {
67
- [key: string]: string;
68
- }): Promise<void> {
69
- const fontsToLoad = { ...fonts }; //clone our input so we can safely mutate it.
70
-
71
- document.fonts.forEach(fontFace => {
72
- // If the family is defined with quotes in CSS (e.g. `font-family: "Noto Sans"),
73
- // those quotes may be preserved JS, depending on the browser.
74
- const normalizedFamily = fontFace.family.replace(/"/g, '');
75
- if (fontsToLoad[normalizedFamily]) {
76
- // remove the font from the set to load
77
- delete fontsToLoad[normalizedFamily];
78
- }
79
- });
80
-
81
- return Promise.all(
82
- Object.values(fontsToLoad).map(href => {
83
- return checkAndLoadStyle(href).catch(() => {
84
- // Don't fail loading process for fonts, since the components
85
- // should still be reasonably usable.
86
- console.info(`genesys-spark: couldn't load font style ${href}`);
87
- });
88
- })
89
- ).then(() => {}); // flatten the promise array
90
- }
@@ -1,69 +0,0 @@
1
- import { getAssetsOrigin, getFontOrigin } from '../src/hosts';
2
-
3
- const NON_STANDARD_DOMAINS = [
4
- 'inindca.com',
5
- 'inintca.com',
6
- 'mypurecloud.com.au',
7
- 'mypurecloud.com',
8
- 'mypurecloud.de',
9
- 'mypurecloud.ie',
10
- 'mypurecloud.jp'
11
- ];
12
-
13
- describe('The hosts module', () => {
14
- beforeEach(() => {
15
- window.IS_DEV_MODE = false;
16
- });
17
-
18
- describe('when determining asset domains', () => {
19
- it('Will return the correct domain for pages in a `pure.cloud` region', () => {
20
- setLocation('https://uis.region.pure.cloud/page');
21
- expect(getAssetsOrigin()).toBe('https://app.region.pure.cloud');
22
- });
23
-
24
- it('Will return a default domain for non-genesys hosted pages', () => {
25
- setLocation('https://www.example.com/page');
26
- expect(getAssetsOrigin()).toBe('https://app.mypurecloud.com');
27
- });
28
-
29
- NON_STANDARD_DOMAINS.forEach(domain => {
30
- const withSubDomain = `https://dummySubdomain.${domain}/page`;
31
- it(`Will recognize ${withSubDomain} as a Genesys domain`, () => {
32
- setLocation(withSubDomain);
33
- expect(getAssetsOrigin()).toBe(`https://app.${domain}`);
34
- });
35
- });
36
- });
37
-
38
- describe('when determining font domains', () => {
39
- it('Will return the correct domain for pages in a `pure.cloud` region', () => {
40
- setLocation('https://uis.region.pure.cloud/page');
41
- expect(getFontOrigin()).toBe('https://app.region.pure.cloud');
42
- });
43
-
44
- it('Will return a default domain for non-genesys hosted pages', () => {
45
- setLocation('https://www.example.com/page');
46
- expect(getFontOrigin()).toBe('https://app.mypurecloud.com');
47
- });
48
-
49
- NON_STANDARD_DOMAINS.forEach(domain => {
50
- const withSubDomain = `https://dummySubdomain.${domain}/page`;
51
- it(`Will recognize ${withSubDomain} as a Genesys domain`, () => {
52
- setLocation(withSubDomain);
53
- expect(getFontOrigin()).toBe(`https://app.${domain}`);
54
- });
55
- });
56
- });
57
- });
58
-
59
- /**
60
- * This is an absolutely disgusting abdication of the type system, but it's a
61
- * damn sight simpler than most ways to get dynamic per-test location updates.
62
- * See: https://github.com/jestjs/jest/issues/5124
63
- */
64
- function setLocation(location: string) {
65
- //@ts-ignore
66
- delete window.location;
67
- //@ts-ignore
68
- window.location = new URL(location);
69
- }
package/test/intl.spec.ts DELETED
@@ -1,104 +0,0 @@
1
- import {
2
- determineDisplayLocale,
3
- dateTimeFormat,
4
- relativeTimeFormat
5
- } from '../src/intl';
6
-
7
- describe('The intl module', () => {
8
- beforeEach(() => {
9
- // Reset the Dom
10
- document.documentElement.innerHTML = '<head></head><body></body>';
11
- // Remove language attribute from <html>
12
- document.documentElement.removeAttribute('lang');
13
- // Reset/set navigator.language to a known value
14
- Object.defineProperty(window.navigator, 'language', {
15
- value: 'yy-YY',
16
- configurable: true
17
- });
18
- });
19
-
20
- describe('When determining what locale to use', () => {
21
- test('It will determine the display locale from <body> if no locale is provided', () => {
22
- document.body.setAttribute('lang', 'xx-XX');
23
- expect(determineDisplayLocale()).toBe('xx-XX');
24
- });
25
- test('It will determine the display locale from <html> if no locale is provided', () => {
26
- document.documentElement.setAttribute('lang', 'xx-XX');
27
- expect(determineDisplayLocale()).toBe('xx-XX');
28
- });
29
- test('Given an element with a language attribute, it will determine the locale from that tag', () => {
30
- const target = document.createElement('div');
31
- target.setAttribute('lang', 'xx-XX');
32
- expect(determineDisplayLocale(target)).toBe('xx-XX');
33
- });
34
- test("Given an element without a language attribute, it will check the element's ancestors for a language attribute", () => {
35
- const localeOwner = document.createElement('div');
36
- localeOwner.setAttribute('lang', 'xx-XX');
37
- localeOwner.innerHTML =
38
- '<div><div><span class="target"></span></div></div>';
39
- const target =
40
- localeOwner.querySelector<HTMLElement>('.target') || undefined;
41
- expect(target).not.toBeUndefined();
42
- expect(determineDisplayLocale(target)).toBe('xx-XX');
43
- });
44
- test("If no language tag is found, uses the browser's language", () => {
45
- expect(determineDisplayLocale()).toBe('yy-YY');
46
- });
47
- test('If given a partial match to the browser language, it will pull the region from the browser', () => {
48
- document.body.setAttribute('lang', 'yy');
49
- expect(determineDisplayLocale()).toBe('yy-YY');
50
- });
51
- });
52
-
53
- describe('When creating a DateTimeFormat', () => {
54
- const formatOptions: Intl.DateTimeFormatOptions = {};
55
- beforeEach(() => {
56
- jest.resetAllMocks();
57
- jest.spyOn(Intl, 'DateTimeFormat');
58
- });
59
- it('Calls through to the browser implementation', () => {
60
- dateTimeFormat('xx-XX', formatOptions);
61
- expect(Intl.DateTimeFormat).toHaveBeenCalledWith('xx-XX', formatOptions);
62
- });
63
- it('The locale is optional and will defer to `determineDisplayLocale`', () => {
64
- document.body.setAttribute('lang', 'xx-XX');
65
- dateTimeFormat(formatOptions);
66
- expect(Intl.DateTimeFormat).toHaveBeenCalledWith('xx-XX', formatOptions);
67
- });
68
- it('Maintains optional format options', () => {
69
- dateTimeFormat('en-US');
70
- expect(Intl.DateTimeFormat).toHaveBeenCalledWith('en-US', undefined);
71
- });
72
- });
73
-
74
- describe('When creating a RelativeTimeFormat', () => {
75
- const formatOptions: Intl.RelativeTimeFormatOptions = {};
76
- beforeEach(() => {
77
- jest.resetAllMocks();
78
- // This has to be different than the DateTimeFormat mock - probably because of some ES6 class
79
- // thing that I can't be bothered to figure out.
80
- Object.defineProperty(Intl, 'RelativeTimeFormat', {
81
- value: jest.fn()
82
- });
83
- });
84
- it('Calls through to the browser implementation', () => {
85
- relativeTimeFormat('xx-XX', formatOptions);
86
- expect(Intl.RelativeTimeFormat).toHaveBeenCalledWith(
87
- 'xx-XX',
88
- formatOptions
89
- );
90
- });
91
- it('The locale is optional and will defer to `determineDisplayLocale`', () => {
92
- document.body.setAttribute('lang', 'xx-XX');
93
- relativeTimeFormat(formatOptions);
94
- expect(Intl.RelativeTimeFormat).toHaveBeenCalledWith(
95
- 'xx-XX',
96
- formatOptions
97
- );
98
- });
99
- it('Maintains optional format options', () => {
100
- relativeTimeFormat('en-US');
101
- expect(Intl.RelativeTimeFormat).toHaveBeenCalledWith('en-US', undefined);
102
- });
103
- });
104
- });
@@ -1,150 +0,0 @@
1
- import {
2
- checkAndLoadFonts,
3
- checkAndLoadScript,
4
- checkAndLoadStyle
5
- } from '../src/loading';
6
-
7
- const SCRIPT_URL = 'https://localhost/script.js';
8
- const STYLE_URL = 'https://localhost/style.css';
9
- const FONTS = {
10
- Font1: `font1.css`,
11
- Font2: `font2.css`
12
- };
13
-
14
- describe('The loading module', () => {
15
- afterEach(() => {
16
- document.head.innerHTML = '';
17
- document.body.innerHTML = '';
18
- });
19
-
20
- describe('checkAndLoadScript', () => {
21
- test('will create a new script tag and wait for it to load', async () => {
22
- const promise = checkAndLoadScript(SCRIPT_URL);
23
- const tag = document.querySelector(`script[src="${SCRIPT_URL}"]`);
24
-
25
- expect(tag).not.toBeNull(); // The tag was created
26
- tag?.dispatchEvent(new Event('load')); // The promise will resolve
27
-
28
- await expect(promise).resolves.toBe(undefined);
29
- });
30
- test('will fail if the script fails to load', async () => {
31
- const promise = checkAndLoadScript(SCRIPT_URL);
32
- const tag = document.querySelector(`script[src="${SCRIPT_URL}"]`);
33
-
34
- expect(tag).not.toBeNull(); // The tag was created
35
- tag?.dispatchEvent(new Event('error')); // The promise will reject
36
-
37
- await expect(promise).rejects.toContain(SCRIPT_URL);
38
- });
39
- test('will not create a tag if one already exists', async () => {
40
- const script = document.createElement('script');
41
- script.setAttribute('src', SCRIPT_URL);
42
- document.body.appendChild(script);
43
-
44
- await checkAndLoadScript(SCRIPT_URL); // Should resolve immediately
45
- const tags = document.querySelectorAll(`script[src="${SCRIPT_URL}"]`);
46
- expect(tags.length).toBe(1); // A second tag was not created
47
- });
48
- });
49
- describe('checkAndLoadStyle', () => {
50
- test('will create a new link tag and wait for it to load', async () => {
51
- const promise = checkAndLoadStyle(STYLE_URL);
52
- const tag = document.querySelector(
53
- `link[href="${STYLE_URL}"][rel="stylesheet"]`
54
- );
55
-
56
- expect(tag).not.toBeNull(); // The tag was created
57
- tag?.dispatchEvent(new Event('load')); // The promise will resolve
58
-
59
- await expect(promise).resolves.toBe(undefined);
60
- });
61
- test('will fail if the style fails to load', async () => {
62
- const promise = checkAndLoadStyle(STYLE_URL);
63
- const tag = document.querySelector(
64
- `link[href="${STYLE_URL}"][rel="stylesheet"]`
65
- );
66
-
67
- expect(tag).not.toBeNull(); // The tag was created
68
- tag?.dispatchEvent(new Event('error')); // The promise will reject
69
-
70
- await expect(promise).rejects.toContain(STYLE_URL);
71
- });
72
- test('will not create a tag if one already exists', async () => {
73
- const link = document.createElement('link');
74
- link.setAttribute('href', STYLE_URL);
75
- link.setAttribute('rel', 'stylesheet');
76
- document.body.appendChild(link);
77
-
78
- await checkAndLoadStyle(STYLE_URL); // Should resolve immediately
79
- const tags = document.querySelectorAll(`link[href="${STYLE_URL}"]`);
80
- expect(tags.length).toBe(1); // A second tag was not created
81
- });
82
- });
83
- describe('checkAndLoadFonts', () => {
84
- let documentFonts: Array<any> = [];
85
-
86
- beforeEach(() => {
87
- documentFonts = [];
88
- //@ts-ignore - needed to be able to stub out font API
89
- document.fonts = documentFonts;
90
- });
91
-
92
- test('Will load missing fonts', async () => {
93
- const promise = checkAndLoadFonts(FONTS);
94
- const tag1 = document.querySelector(`link[href="font1.css"]`);
95
- const tag2 = document.querySelector(`link[href="font2.css"]`);
96
-
97
- expect(tag1).not.toBeNull();
98
- expect(tag2).not.toBeNull();
99
-
100
- tag1?.dispatchEvent(new Event('load'));
101
- tag2?.dispatchEvent(new Event('load'));
102
-
103
- await expect(promise).resolves.toBe(undefined);
104
- });
105
-
106
- test('Will not load fonts that are already loaded', async () => {
107
- documentFonts.push({ family: 'Font2' });
108
-
109
- const promise = checkAndLoadFonts(FONTS);
110
- const tag1 = document.querySelector(`link[href="font1.css"]`);
111
- const tag2 = document.querySelector(`link[href="font2.css"]`);
112
-
113
- expect(tag1).not.toBeNull();
114
- expect(tag2).toBeNull();
115
-
116
- tag1?.dispatchEvent(new Event('load'));
117
-
118
- await expect(promise).resolves.toBe(undefined);
119
- });
120
-
121
- test('Ignores quotes on the family when checking for loaded fonts', async () => {
122
- documentFonts.push({ family: '"Font2"' });
123
-
124
- const promise = checkAndLoadFonts(FONTS);
125
- const tag1 = document.querySelector(`link[href="font1.css"]`);
126
- const tag2 = document.querySelector(`link[href="font2.css"]`);
127
-
128
- expect(tag1).not.toBeNull();
129
- expect(tag2).toBeNull();
130
-
131
- tag1?.dispatchEvent(new Event('load'));
132
-
133
- await expect(promise).resolves.toBe(undefined);
134
- });
135
-
136
- test('Still resolves even if fonts fail to load', async () => {
137
- const promise = checkAndLoadFonts(FONTS);
138
- const tag1 = document.querySelector(`link[href="font1.css"]`);
139
- const tag2 = document.querySelector(`link[href="font2.css"]`);
140
-
141
- expect(tag1).not.toBeNull();
142
- expect(tag2).not.toBeNull();
143
-
144
- tag1?.dispatchEvent(new Event('error'));
145
- tag2?.dispatchEvent(new Event('error'));
146
-
147
- await expect(promise).resolves.toBe(undefined);
148
- });
149
- });
150
- });
package/tsconfig.json DELETED
@@ -1,10 +0,0 @@
1
- {
2
- "extends": "@tsconfig/strictest/tsconfig.json",
3
- "compilerOptions": {
4
- "noEmitOnError": true,
5
- "outDir": "dist",
6
- "declaration": true,
7
- "lib": ["ESNext.Intl", "DOM"]
8
- },
9
- "include": ["src", "test"]
10
- }