lighthouse 10.0.0-dev.20230213 → 10.0.1

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.
Files changed (75) hide show
  1. package/core/audits/dobetterweb/doctype.d.ts +3 -2
  2. package/core/audits/dobetterweb/doctype.js +15 -4
  3. package/core/audits/dobetterweb/paste-preventing-inputs.js +2 -2
  4. package/core/gather/driver/network-monitor.js +1 -3
  5. package/core/gather/gatherers/bf-cache-failures.js +7 -8
  6. package/package.json +1 -1
  7. package/shared/localization/locales/en-US.json +1 -1
  8. package/shared/localization/locales/en-XL.json +1 -1
  9. package/.codecov.yml +0 -22
  10. package/.cz-config.js +0 -24
  11. package/.gitattributes +0 -5
  12. package/.mailmap +0 -6
  13. package/CODE_OF_CONDUCT.md +0 -93
  14. package/eslint-local-rules.cjs +0 -106
  15. package/flow-report/test/app-test.d.ts +0 -7
  16. package/flow-report/test/app-test.tsx +0 -52
  17. package/flow-report/test/common-test.d.ts +0 -7
  18. package/flow-report/test/common-test.tsx +0 -103
  19. package/flow-report/test/flow-report-pptr-test.d.ts +0 -7
  20. package/flow-report/test/flow-report-pptr-test.ts +0 -59
  21. package/flow-report/test/header-test.d.ts +0 -7
  22. package/flow-report/test/header-test.tsx +0 -55
  23. package/flow-report/test/run-flow-report-tests.sh +0 -20
  24. package/flow-report/test/sample-flow.d.ts +0 -7
  25. package/flow-report/test/sample-flow.ts +0 -17
  26. package/flow-report/test/setup/env-setup.d.ts +0 -11
  27. package/flow-report/test/setup/env-setup.ts +0 -55
  28. package/flow-report/test/sidebar/flow-test.d.ts +0 -7
  29. package/flow-report/test/sidebar/flow-test.tsx +0 -65
  30. package/flow-report/test/sidebar/sidebar-test.d.ts +0 -7
  31. package/flow-report/test/sidebar/sidebar-test.tsx +0 -116
  32. package/flow-report/test/summary/category-test.d.ts +0 -7
  33. package/flow-report/test/summary/category-test.tsx +0 -206
  34. package/flow-report/test/summary/summary-test.d.ts +0 -7
  35. package/flow-report/test/summary/summary-test.tsx +0 -124
  36. package/flow-report/test/topbar-test.d.ts +0 -7
  37. package/flow-report/test/topbar-test.tsx +0 -84
  38. package/flow-report/test/util-test.d.ts +0 -7
  39. package/flow-report/test/util-test.tsx +0 -133
  40. package/flow-report/test/wrappers/category-score-test.d.ts +0 -7
  41. package/flow-report/test/wrappers/category-score-test.tsx +0 -84
  42. package/flow-report/test/wrappers/markdown-test.d.ts +0 -7
  43. package/flow-report/test/wrappers/markdown-test.tsx +0 -17
  44. package/report/test/clients/bundle-test.js +0 -65
  45. package/report/test/generator/file-namer-test.js +0 -27
  46. package/report/test/generator/report-generator-test.js +0 -160
  47. package/report/test/renderer/__snapshots__/report-renderer-axe-test.js.snap +0 -15
  48. package/report/test/renderer/category-renderer-test.js +0 -575
  49. package/report/test/renderer/components-test.js +0 -124
  50. package/report/test/renderer/crc-details-renderer-test.js +0 -116
  51. package/report/test/renderer/details-renderer-test.js +0 -882
  52. package/report/test/renderer/dom-test.js +0 -257
  53. package/report/test/renderer/element-screenshot-renderer-test.js +0 -183
  54. package/report/test/renderer/i18n-formatter-test.js +0 -179
  55. package/report/test/renderer/performance-category-renderer-test.js +0 -417
  56. package/report/test/renderer/pwa-category-renderer-test.js +0 -301
  57. package/report/test/renderer/report-renderer-axe-test.js +0 -85
  58. package/report/test/renderer/report-renderer-test.js +0 -268
  59. package/report/test/renderer/report-ui-features-test.js +0 -773
  60. package/report/test/renderer/report-utils-test.js +0 -219
  61. package/report/test/renderer/snippet-renderer-test.js +0 -291
  62. package/report/test/renderer/text-encoding-test.js +0 -43
  63. package/report/test-assets/faux-psi-template.html +0 -177
  64. package/report/test-assets/faux-psi.d.ts +0 -34
  65. package/report/test-assets/faux-psi.js +0 -168
  66. package/report/test-assets/lhr-3.0.0.json +0 -2332
  67. package/report/test-assets/lhr-4.3.0.json +0 -4754
  68. package/report/test-assets/lhr-5.0.0.json +0 -5994
  69. package/report/test-assets/lhr-6.0.0.json +0 -7222
  70. package/report/test-assets/lhr-8.5.0.json +0 -8679
  71. package/shared/test/localization/format-test.js +0 -430
  72. package/shared/test/localization/locales-test.js +0 -45
  73. package/shared/test/localization/swap-locale-test.js +0 -127
  74. package/shared/test/util-test.js +0 -214
  75. package/vercel.json +0 -6
@@ -1,257 +0,0 @@
1
- /**
2
- * @license Copyright 2017 The Lighthouse Authors. All Rights Reserved.
3
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
4
- * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
5
- */
6
-
7
- import assert from 'assert/strict';
8
-
9
- import jestMock from 'jest-mock';
10
- import jsdom from 'jsdom';
11
-
12
- import {DOM} from '../../renderer/dom.js';
13
- import {I18nFormatter} from '../../renderer/i18n-formatter.js';
14
- import {Globals} from '../../renderer/report-globals.js';
15
-
16
- describe('DOM', () => {
17
- /** @type {DOM} */
18
- let dom;
19
- let window;
20
- let nativeCreateObjectURL;
21
-
22
- before(() => {
23
- Globals.apply({
24
- providedStrings: {},
25
- i18n: new I18nFormatter('en'),
26
- reportJson: null,
27
- });
28
- window = new jsdom.JSDOM().window;
29
-
30
- // The Node version of URL.createObjectURL isn't compatible with the jsdom blob type,
31
- // so we stub it.
32
- nativeCreateObjectURL = URL.createObjectURL;
33
- URL.createObjectURL = jestMock.fn(_ => `https://fake-origin/blahblah-blobid`);
34
-
35
- dom = new DOM(window.document);
36
- dom.setLighthouseChannel('someChannel');
37
- });
38
-
39
- after(() => {
40
- Globals.i18n = undefined;
41
- URL.createObjectURL = nativeCreateObjectURL;
42
- });
43
-
44
- describe('createElement', () => {
45
- it('creates a simple element using default values', () => {
46
- const el = dom.createElement('div');
47
- assert.equal(el.localName, 'div');
48
- assert.equal(el.className, '');
49
- assert.equal(el.hasAttributes(), false);
50
- });
51
-
52
- it('creates an element from parameters', () => {
53
- const el = dom.createElement('div', ' class1 class2\n');
54
- assert.equal(el.localName, 'div');
55
- assert.equal(el.className, 'class1 class2');
56
- });
57
-
58
- it('creates an svg element from parameters', () => {
59
- const el = dom.createElementNS('http://www.w3.org/2000/svg', 'svg', ' class1 class2\n');
60
- assert.equal(el.localName, 'svg');
61
- assert.equal(el.className.baseVal, 'class1 class2');
62
- });
63
- });
64
-
65
- describe('createComponent', () => {
66
- it('should create a component', () => {
67
- const component = dom.createComponent('audit');
68
- assert.ok(component.querySelector('.lh-audit'));
69
- });
70
-
71
- it('fails when component cannot be found', () => {
72
- assert.throws(() => dom.createComponent('unknown-component'));
73
- });
74
-
75
- it('does not inject duplicate styles', () => {
76
- const clone = dom.createComponent('snippet');
77
- const clone2 = dom.createComponent('snippet');
78
- assert.ok(clone.querySelector('style'));
79
- assert.ok(!clone2.querySelector('style'));
80
- });
81
- });
82
-
83
- describe('convertMarkdownLinkSnippets', () => {
84
- it('correctly converts links', () => {
85
- let result = dom.convertMarkdownLinkSnippets(
86
- 'Some [link](https://example.com/foo). [Learn more](http://example.com).');
87
- assert.equal(result.innerHTML,
88
- 'Some <a rel="noopener" target="_blank" href="https://example.com/foo">link</a>. ' +
89
- '<a rel="noopener" target="_blank" href="http://example.com/">Learn more</a>.');
90
-
91
- result = dom.convertMarkdownLinkSnippets('[link](https://example.com/foo)');
92
- assert.equal(result.innerHTML,
93
- '<a rel="noopener" target="_blank" href="https://example.com/foo">link</a>',
94
- 'just a link');
95
-
96
- result = dom.convertMarkdownLinkSnippets(
97
- '[ Link ](https://example.com/foo) and some text afterwards.');
98
- assert.equal(result.innerHTML,
99
- '<a rel="noopener" target="_blank" href="https://example.com/foo"> Link </a> ' +
100
- 'and some text afterwards.', 'link with spaces in brackets');
101
- });
102
-
103
- it('correctly converts code snippets', () => {
104
- let result = dom.convertMarkdownLinkSnippets(
105
- 'Some `code`. [Learn more](http://example.com).');
106
- assert.equal(result.innerHTML,
107
- '<span>Some <code>code</code>. </span>' +
108
- '<a rel="noopener" target="_blank" href="http://example.com/">Learn more</a>.');
109
-
110
- result = dom.convertMarkdownLinkSnippets(
111
- '[link with `code`](https://example.com/foo) and some text afterwards.');
112
- assert.equal(result.innerHTML,
113
- '<a rel="noopener" target="_blank" href="https://example.com/foo">' +
114
- '<span>link with <code>code</code></span>' +
115
- '</a> and some text afterwards.', 'link with code snippet inside');
116
- });
117
-
118
- it('handles invalid urls', () => {
119
- const text = 'Text has [bad](https:///) link.';
120
- assert.throws(() => {
121
- dom.convertMarkdownLinkSnippets(text);
122
- });
123
- });
124
-
125
- it('ignores links that do not start with http', () => {
126
- const snippets = [
127
- 'Sentence with [link](/local/path).',
128
- 'Sentence with [link](javascript:console.log("pwned")).',
129
- 'Sentence with [link](chrome://settings#give-my-your-password).',
130
- ];
131
-
132
- for (const text of snippets) {
133
- const result = dom.convertMarkdownLinkSnippets(text);
134
- assert.equal(result.innerHTML, text);
135
- }
136
- });
137
-
138
- it('handles the case of [text]... [text](url)', () => {
139
- const text = 'Ensuring `<td>` cells using the `[headers]` are good. ' +
140
- '[Learn more](https://dequeuniversity.com/rules/axe/3.1/td-headers-attr).';
141
- const result = dom.convertMarkdownLinkSnippets(text);
142
- assert.equal(result.innerHTML,
143
- '<span>Ensuring <code>&lt;td&gt;</code> cells using the <code>[headers]</code> are ' +
144
- 'good. </span><a rel="noopener" target="_blank" href="https://dequeuniversity.com/rules/axe/3.1/td-headers-attr">Learn more</a>.');
145
- });
146
-
147
- it('appends utm params to the URLs with https://developers.google.com origin', () => {
148
- const text = '[Learn more](https://developers.google.com/web/tools/lighthouse/audits/description).';
149
-
150
- const result = dom.convertMarkdownLinkSnippets(text);
151
- assert.equal(result.innerHTML, '<a rel="noopener" target="_blank" href="https://developers.google.com/web/tools/lighthouse/audits/description?utm_source=lighthouse&amp;utm_medium=someChannel">Learn more</a>.');
152
- });
153
-
154
- it('appends utm params to the URLs with https://web.dev origin', () => {
155
- const text = '[Learn more](https://web.dev/tap-targets/).';
156
-
157
- const result = dom.convertMarkdownLinkSnippets(text);
158
- assert.equal(result.innerHTML, '<a rel="noopener" target="_blank" href="https://web.dev/tap-targets/?utm_source=lighthouse&amp;utm_medium=someChannel">Learn more</a>.');
159
- });
160
-
161
- it('appends utm params to the URLs with https://developer.chrome.com origin', () => {
162
- const text = '[Learn more](https://developer.chrome.com/docs/lighthouse/seo/tap-targets/).';
163
-
164
- const result = dom.convertMarkdownLinkSnippets(text);
165
- assert.equal(result.innerHTML, '<a rel="noopener" target="_blank" href="https://developer.chrome.com/docs/lighthouse/seo/tap-targets/?utm_source=lighthouse&amp;utm_medium=someChannel">Learn more</a>.');
166
- });
167
-
168
- it('doesn\'t append utm params to other (non-docs) origins', () => {
169
- const text = '[Learn more](https://example.com/info).';
170
-
171
- const result = dom.convertMarkdownLinkSnippets(text);
172
- assert.equal(result.innerHTML, '<a rel="noopener" target="_blank" href="https://example.com/info">Learn more</a>.');
173
- });
174
- });
175
-
176
- describe('convertMarkdownCodeSnippets', () => {
177
- it('correctly converts links', () => {
178
- const result = dom.convertMarkdownCodeSnippets(
179
- 'Here is some `code`, and then some `more code`, and yet event `more`.');
180
- assert.equal(result.innerHTML, 'Here is some <code>code</code>, and then some ' +
181
- '<code>more code</code>, and yet event <code>more</code>.');
182
- });
183
- });
184
-
185
- describe('safelySetHref', () => {
186
- it('sets href for safe destinations', () => {
187
- [
188
- 'https://safe.com/',
189
- 'http://safe.com/',
190
- ].forEach(url => {
191
- const a = dom.createElement('a');
192
- dom.safelySetHref(a, url);
193
- expect(a.href).toEqual(url);
194
- });
195
- });
196
-
197
- it('sets href for safe in-page named anchors', () => {
198
- const a = dom.createElement('a');
199
- dom.safelySetHref(a, '#footer');
200
- expect(a.href).toEqual('about:blank#footer');
201
- });
202
-
203
- it('doesnt set href if destination is unsafe', () => {
204
- [
205
- 'javascript:evil()',
206
- 'data:text/html;base64,abcdef',
207
- 'data:application/json;base64,abcdef',
208
- 'ftp://evil.com/',
209
- 'blob:http://example.com/ca6df701-9c67-49fd-a787',
210
- 'intent://example.com',
211
- 'filesystem:http://localhost/img.png',
212
- 'ws://evilchat.com/',
213
- 'wss://evilchat.com/',
214
- 'about:about',
215
- 'chrome://chrome-urls/',
216
- ].forEach(url => {
217
- const a = dom.createElement('a');
218
- dom.safelySetHref(a, url);
219
-
220
- expect(a.href).toEqual('');
221
- expect(a.getAttribute('href')).toEqual(null);
222
- });
223
- });
224
-
225
- it('handles if url is undefined (because of proto roundtrip)', () => {
226
- const a = dom.createElement('a');
227
- dom.safelySetHref(a, undefined);
228
- expect(a.href).toEqual('');
229
- });
230
- });
231
-
232
- describe('safelySetBlobHref', () => {
233
- it('sets href for safe blob types', () => {
234
- [
235
- new window.Blob([JSON.stringify({test: 1234})], {type: 'application/json'}),
236
- new window.Blob([`<html><h1>hello`], {type: 'text/html'}),
237
- ].forEach(blob => {
238
- const a = dom.createElement('a');
239
- dom.safelySetBlobHref(a, blob);
240
- expect(a.href).toEqual('https://fake-origin/blahblah-blobid');
241
- });
242
- });
243
-
244
- it('throws with unsupported blob types', () => {
245
- [
246
- new window.Blob(['<xml>'], {type: 'image/svg+xml'}),
247
- new window.Blob(['evilbinary'], {type: 'application/octet-stream'}),
248
- new window.Blob(['fake']),
249
- ].forEach(blob => {
250
- const a = dom.createElement('a');
251
- expect(() => {
252
- dom.safelySetBlobHref(a, blob);
253
- }).toThrowError(/Unsupported blob/);
254
- });
255
- });
256
- });
257
- });
@@ -1,183 +0,0 @@
1
- /**
2
- * @license Copyright 2020 Google Inc. All Rights Reserved.
3
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
4
- * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
5
- */
6
-
7
- import jsdom from 'jsdom';
8
-
9
- import {ElementScreenshotRenderer} from '../../renderer/element-screenshot-renderer.js';
10
- import {I18nFormatter} from '../../renderer/i18n-formatter.js';
11
- import {DOM} from '../../renderer/dom.js';
12
- import {Globals} from '../../renderer/report-globals.js';
13
-
14
- /**
15
- * @param {{left: number, top: number, width: number, height:number}} opts
16
- * @return {LH.Artifacts.Rect}
17
- */
18
- function makeRect(opts) {
19
- return {
20
- ...opts,
21
- right: opts.left + opts.width,
22
- bottom: opts.top + opts.height,
23
- };
24
- }
25
-
26
- describe('ElementScreenshotRenderer', () => {
27
- let dom;
28
-
29
- before(() => {
30
- Globals.apply({
31
- providedStrings: {},
32
- i18n: new I18nFormatter('en'),
33
- reportJson: null,
34
- });
35
-
36
- const {document} = new jsdom.JSDOM().window;
37
- dom = new DOM(document);
38
- Globals.resetUniqueSuffix();
39
- });
40
-
41
- after(() => {
42
- Globals.i18n = undefined;
43
- });
44
-
45
- it('renders screenshot', () => {
46
- const fullPageScreenshot = {
47
- width: 1000,
48
- height: 1000,
49
- };
50
- const elementRectSC = makeRect({
51
- left: 50,
52
- top: 50,
53
- width: 200,
54
- height: 300,
55
- });
56
- const renderContainerSizeDC = {
57
- width: 500,
58
- height: 500,
59
- };
60
- const el = ElementScreenshotRenderer.render(
61
- dom,
62
- fullPageScreenshot,
63
- elementRectSC,
64
- renderContainerSizeDC
65
- );
66
-
67
- const htmlFormatted = el.innerHTML.replace(/(<\w+ )/g, '\n$1');
68
- /* eslint-disable max-len */
69
- expect(htmlFormatted).toMatchInlineSnapshot(`
70
- "
71
- <div class=\\"lh-element-screenshot__content\\">
72
- <div class=\\"lh-element-screenshot__image\\" style=\\"width: 500px; height: 500px; background-position-y: 0px; background-position-x: 0px; background-size: 1000px 1000px;\\">
73
- <div class=\\"lh-element-screenshot__mask\\" style=\\"width: 500px; height: 500px; clip-path: url(#clip-0);\\">
74
- <svg height=\\"0\\" width=\\"0\\"> <defs>
75
- <clipPath clipPathUnits=\\"objectBoundingBox\\" id=\\"clip-0\\">
76
- <polygon points=\\"0,0 1,0 1,0.1 0,0.1\\"></polygon>
77
- <polygon points=\\"0,0.7 1,0.7 1,1 0,1\\"></polygon>
78
- <polygon points=\\"0,0.1 0.1,0.1 0.1,0.7 0,0.7\\"></polygon>
79
- <polygon points=\\"0.5,0.1 1,0.1 1,0.7 0.5,0.7\\"></polygon></clipPath> </defs> </svg> </div>
80
- <div class=\\"lh-element-screenshot__element-marker\\" style=\\"width: 200px; height: 300px; left: 50px; top: 50px;\\"></div> </div> </div> "
81
- `);
82
- /* eslint-enable max-len */
83
- });
84
-
85
- it('returns null if element is out of bounds', () => {
86
- const fullPageScreenshot = {
87
- width: 1000,
88
- height: 1000,
89
- };
90
- const elementRectSC = makeRect({
91
- left: 50,
92
- top: 5000,
93
- width: 200,
94
- height: 300,
95
- });
96
- const renderContainerSizeDC = {
97
- width: 500,
98
- height: 500,
99
- };
100
- expect(ElementScreenshotRenderer.render(
101
- dom,
102
- fullPageScreenshot,
103
- elementRectSC,
104
- renderContainerSizeDC
105
- )).toBe(null);
106
- });
107
-
108
- describe('getScreenshotPositions', () => {
109
- it('centers the screenshot on the highlighted area', () => {
110
- expect(
111
- ElementScreenshotRenderer.getScreenshotPositions(
112
- {left: 400, top: 500, width: 100, height: 40},
113
- {width: 412, height: 300},
114
- {width: 1300, height: 5000}
115
- )
116
- ).toMatchObject({
117
- screenshot: {
118
- left: 244,
119
- top: 370,
120
- },
121
- clip: {
122
- left: 156,
123
- top: 130,
124
- },
125
- });
126
- });
127
-
128
- it('contains the screenshot within the display area if the clip is in the top left', () => {
129
- expect(
130
- ElementScreenshotRenderer.getScreenshotPositions(
131
- {left: 0, top: 0, width: 100, height: 40},
132
- {width: 412, height: 300},
133
- {width: 412, height: 5000}
134
- )
135
- ).toMatchObject({
136
- screenshot: {
137
- left: 0,
138
- top: 0,
139
- },
140
- clip: {
141
- left: 0,
142
- top: 0,
143
- },
144
- });
145
- });
146
-
147
- it('contains the screenshot within the display area if the clip is in the bottom right', () => {
148
- expect(
149
- ElementScreenshotRenderer.getScreenshotPositions(
150
- {left: 300, top: 4950, width: 100, height: 40},
151
- {width: 412, height: 300},
152
- {width: 412, height: 5000}
153
- )
154
- ).toMatchObject({
155
- screenshot: {
156
- left: 0,
157
- top: 4700,
158
- },
159
- clip: {
160
- left: 300,
161
- top: 250,
162
- },
163
- });
164
-
165
- expect(
166
- ElementScreenshotRenderer.getScreenshotPositions(
167
- {left: 300, top: 4950, width: 100, height: 40},
168
- {width: 200, height: 300},
169
- {width: 412, height: 5000}
170
- )
171
- ).toMatchObject({
172
- screenshot: {
173
- left: 212,
174
- top: 4700,
175
- },
176
- clip: {
177
- left: 88,
178
- top: 250,
179
- },
180
- });
181
- });
182
- });
183
- });
@@ -1,179 +0,0 @@
1
- /**
2
- * @license Copyright 2020 The Lighthouse Authors. All Rights Reserved.
3
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
4
- * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
5
- */
6
-
7
- import assert from 'assert/strict';
8
-
9
- import {I18nFormatter} from '../../renderer/i18n-formatter.js';
10
-
11
- const NBSP = '\xa0';
12
-
13
- describe('i18n formatter', () => {
14
- it('formats a number', () => {
15
- const i18n = new I18nFormatter('en');
16
- assert.strictEqual(i18n.formatNumber(10), '10');
17
- assert.strictEqual(i18n.formatNumber(100.01), '100.01');
18
- assert.strictEqual(i18n.formatNumber(13000.456), '13,000.456');
19
- assert.strictEqual(i18n.formatNumber(13000.456444), '13,000.456');
20
-
21
- assert.strictEqual(i18n.formatNumber(10, 0.1), '10.0');
22
- assert.strictEqual(i18n.formatNumber(100.01, 0.1), '100.0');
23
- assert.strictEqual(i18n.formatNumber(13000.456, 0.1), '13,000.5');
24
-
25
- assert.strictEqual(i18n.formatNumber(0), '0');
26
- assert.strictEqual(i18n.formatNumber(-0), '0');
27
- assert.strictEqual(i18n.formatNumber(-0, 0.1), '0.0');
28
- assert.strictEqual(i18n.formatNumber(0.000001), '0');
29
- assert.strictEqual(i18n.formatNumber(-0.000001), '0');
30
- assert.strictEqual(i18n.formatNumber(0.000001, 0.1), '0.0');
31
- assert.strictEqual(i18n.formatNumber(-0.000001, 0.1), '0.0');
32
-
33
- assert.strictEqual(i18n.formatNumber(10), '10');
34
- assert.strictEqual(i18n.formatNumber(100.01), '100.01');
35
- assert.strictEqual(i18n.formatNumber(13000.456, 0.1), '13,000.5');
36
-
37
- assert.strictEqual(i18n.formatInteger(10), '10');
38
- assert.strictEqual(i18n.formatInteger(100.01), '100');
39
- assert.strictEqual(i18n.formatInteger(13000.6), '13,001');
40
- });
41
-
42
- it('formats a date', () => {
43
- const i18n = new I18nFormatter('en');
44
- const timestamp = i18n.formatDateTime('2017-04-28T23:07:51.189Z');
45
- assert.ok(
46
- timestamp.includes('Apr 27, 2017') ||
47
- timestamp.includes('Apr 28, 2017') ||
48
- timestamp.includes('Apr 29, 2017')
49
- );
50
- });
51
-
52
- it('formats bytes', () => {
53
- const i18n = new I18nFormatter('en');
54
- assert.equal(i18n.formatBytesToKiB(100), `0.098${NBSP}KiB`);
55
- assert.equal(i18n.formatBytesToKiB(100, 0.1), `0.1${NBSP}KiB`);
56
- assert.equal(i18n.formatBytesToKiB(2000, 0.1), `2.0${NBSP}KiB`);
57
- assert.equal(i18n.formatBytesToKiB(1014 * 1024, 0.1), `1,014.0${NBSP}KiB`);
58
- });
59
-
60
- it('formats bytes with different granularities', () => {
61
- const i18n = new I18nFormatter('en');
62
-
63
- let granularity = 10;
64
- assert.strictEqual(i18n.formatBytes(15.0, granularity), `20${NBSP}bytes`);
65
- assert.strictEqual(i18n.formatBytes(15.12345, granularity), `20${NBSP}bytes`);
66
- assert.strictEqual(i18n.formatBytes(14.99999, granularity), `10${NBSP}bytes`);
67
-
68
- granularity = 1;
69
- assert.strictEqual(i18n.formatBytes(15.0, granularity), `15${NBSP}bytes`);
70
- assert.strictEqual(i18n.formatBytes(15.12345, granularity), `15${NBSP}bytes`);
71
- assert.strictEqual(i18n.formatBytes(15.54321, granularity), `16${NBSP}bytes`);
72
-
73
- granularity = 0.1;
74
- assert.strictEqual(i18n.formatBytes(15.0, granularity), `15.0${NBSP}bytes`);
75
- assert.strictEqual(i18n.formatBytes(15.12345, granularity), `15.1${NBSP}bytes`);
76
- assert.strictEqual(i18n.formatBytes(15.19999, granularity), `15.2${NBSP}bytes`);
77
-
78
- granularity = 0.01;
79
- assert.strictEqual(i18n.formatBytes(15.0, granularity), `15.00${NBSP}bytes`);
80
- assert.strictEqual(i18n.formatBytes(15.12345, granularity), `15.12${NBSP}bytes`);
81
- assert.strictEqual(i18n.formatBytes(15.19999, granularity), `15.20${NBSP}bytes`);
82
- });
83
-
84
- it('formats bytes with invalid granularity', () => {
85
- const i18n = new I18nFormatter('en');
86
- const granularity = 0.5;
87
- const originalWarn = console.warn;
88
-
89
- try {
90
- console.warn = () => {};
91
- assert.strictEqual(i18n.formatBytes(15.0, granularity), `15${NBSP}bytes`);
92
- assert.strictEqual(i18n.formatBytes(15.12345, granularity), `15${NBSP}bytes`);
93
- assert.strictEqual(i18n.formatBytes(15.54321, granularity), `16${NBSP}bytes`);
94
- } finally {
95
- console.warn = originalWarn;
96
- }
97
- });
98
-
99
- it('formats kibibytes with different granularities', () => {
100
- const i18n = new I18nFormatter('en');
101
-
102
- let granularity = 10;
103
- assert.strictEqual(i18n.formatBytesToKiB(5 * 1024, granularity), `10${NBSP}KiB`);
104
- assert.strictEqual(i18n.formatBytesToKiB(4 * 1024, granularity), `0${NBSP}KiB`);
105
-
106
- granularity = 1;
107
- assert.strictEqual(i18n.formatBytesToKiB(5 * 1024, granularity), `5${NBSP}KiB`);
108
- assert.strictEqual(i18n.formatBytesToKiB(4 * 1024 + 512, granularity), `5${NBSP}KiB`);
109
- assert.strictEqual(i18n.formatBytesToKiB(4 * 1024 + 511, granularity), `4${NBSP}KiB`);
110
-
111
- granularity = 0.01;
112
- assert.strictEqual(i18n.formatBytesToKiB(5 * 1024, granularity), `5.00${NBSP}KiB`);
113
- assert.strictEqual(i18n.formatBytesToKiB(5 * 1024 - 5, granularity), `5.00${NBSP}KiB`);
114
- assert.strictEqual(i18n.formatBytesToKiB(5 * 1024 - 6, granularity), `4.99${NBSP}KiB`);
115
- });
116
-
117
- it('formats ms', () => {
118
- const i18n = new I18nFormatter('en');
119
- assert.equal(i18n.formatMilliseconds(123, 10), `120${NBSP}ms`);
120
- assert.equal(i18n.formatMilliseconds(2456.5, 0.1), `2,456.5${NBSP}ms`);
121
- assert.equal(i18n.formatMilliseconds(0.000001), `0${NBSP}ms`);
122
- assert.equal(i18n.formatMilliseconds(-0.000001), `0${NBSP}ms`);
123
- });
124
-
125
- it('formats a duration', () => {
126
- const i18n = new I18nFormatter('en');
127
- assert.equal(i18n.formatDuration(60 * 1000), '1m');
128
- assert.equal(i18n.formatDuration(60 * 60 * 1000 + 5000), '1h 5s');
129
- assert.equal(i18n.formatDuration(28 * 60 * 60 * 1000 + 5000), '1d 4h 5s');
130
- });
131
-
132
- it('formats a duration based on locale', () => {
133
- let i18n = new I18nFormatter('de');
134
- assert.equal(i18n.formatDuration(60 * 1000), `1${NBSP}Min.`);
135
- assert.equal(i18n.formatDuration(60 * 60 * 1000 + 5000), `1${NBSP}Std. 5${NBSP}Sek.`);
136
- assert.equal(
137
- i18n.formatDuration(28 * 60 * 60 * 1000 + 5000), `1${NBSP}T 4${NBSP}Std. 5${NBSP}Sek.`);
138
-
139
- // Yes, this is actually backwards (s h d).
140
- i18n = new I18nFormatter('ar');
141
- /* eslint-disable no-irregular-whitespace */
142
- assert.equal(i18n.formatDuration(60 * 1000), `١${NBSP}د`);
143
- assert.equal(i18n.formatDuration(60 * 60 * 1000 + 5000), `١${NBSP}س ٥${NBSP}ث`);
144
- assert.equal(i18n.formatDuration(28 * 60 * 60 * 1000 + 5000), `١ ي ٤ س ٥ ث`);
145
- /* eslint-enable no-irregular-whitespace */
146
- });
147
-
148
- it('formats numbers based on locale', () => {
149
- // Requires full-icu or Intl polyfill.
150
- const number = 12346.858558;
151
-
152
- const i18n = new I18nFormatter('de');
153
- assert.strictEqual(i18n.formatNumber(number), '12.346,859');
154
- assert.strictEqual(i18n.formatBytesToKiB(number, 0.1), `12,1${NBSP}KiB`);
155
- assert.strictEqual(i18n.formatMilliseconds(number, 10), `12.350${NBSP}ms`);
156
- assert.strictEqual(i18n.formatSeconds(number), `12,347${NBSP}Sek.`);
157
- });
158
-
159
- it('uses decimal comma with en-XA test locale', () => {
160
- // Requires full-icu or Intl polyfill.
161
- const number = 12346.858558;
162
-
163
- const i18n = new I18nFormatter('en-XA');
164
- assert.strictEqual(i18n.formatNumber(number), '12.346,859');
165
- assert.strictEqual(i18n.formatBytesToKiB(number, 0.1), `12,1${NBSP}KiB`);
166
- assert.strictEqual(i18n.formatMilliseconds(number, 100), `12.300${NBSP}ms`);
167
- assert.strictEqual(i18n.formatSeconds(number, 1), `12${NBSP}Sek.`);
168
- });
169
-
170
- it('should not crash on unknown locales', () => {
171
- const i18n = new I18nFormatter('unknown-mystery-locale');
172
- const timestamp = i18n.formatDateTime('2017-04-28T23:07:51.189Z');
173
- assert.ok(
174
- timestamp.includes('Apr 27, 2017') ||
175
- timestamp.includes('Apr 28, 2017') ||
176
- timestamp.includes('Apr 29, 2017')
177
- );
178
- });
179
- });