ixbrl-viewer 1.4.68__py3-none-any.whl → 1.4.69__py3-none-any.whl

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.

Potentially problematic release.


This version of ixbrl-viewer might be problematic. Click here for more details.

Files changed (29) hide show
  1. iXBRLViewerPlugin/_version.py +2 -2
  2. iXBRLViewerPlugin/viewer/dist/ixbrlviewer.js +1 -1
  3. {ixbrl_viewer-1.4.68.dist-info → ixbrl_viewer-1.4.69.dist-info}/METADATA +2 -3
  4. {ixbrl_viewer-1.4.68.dist-info → ixbrl_viewer-1.4.69.dist-info}/RECORD +9 -29
  5. {ixbrl_viewer-1.4.68.dist-info → ixbrl_viewer-1.4.69.dist-info}/top_level.txt +0 -1
  6. tests/__init__.py +0 -0
  7. tests/puppeteer/framework/core_elements.js +0 -117
  8. tests/puppeteer/framework/page_objects/doc_frame.js +0 -105
  9. tests/puppeteer/framework/page_objects/fact_details_panel.js +0 -112
  10. tests/puppeteer/framework/page_objects/search_panel.js +0 -73
  11. tests/puppeteer/framework/page_objects/toolbar.js +0 -18
  12. tests/puppeteer/framework/utils.js +0 -3
  13. tests/puppeteer/framework/viewer_page.js +0 -103
  14. tests/puppeteer/puppeteer_test_run_via_intellij.jpg +0 -0
  15. tests/puppeteer/test_filings/filing_documents_smoke_test.zip +0 -0
  16. tests/puppeteer/test_filings/highlights.zip +0 -0
  17. tests/puppeteer/tests/fact_properties.test.js +0 -84
  18. tests/puppeteer/tests/highlight.test.js +0 -186
  19. tests/puppeteer/tests/search.test.js +0 -86
  20. tests/puppeteer/tools/generate.sh +0 -15
  21. tests/unit_tests/__init__.py +0 -0
  22. tests/unit_tests/iXBRLViewerPlugin/__init__.py +0 -0
  23. tests/unit_tests/iXBRLViewerPlugin/mock_arelle.py +0 -41
  24. tests/unit_tests/iXBRLViewerPlugin/test_iXBRLViewer.py +0 -801
  25. tests/unit_tests/iXBRLViewerPlugin/test_xhtmlserialize.py +0 -310
  26. {ixbrl_viewer-1.4.68.dist-info → ixbrl_viewer-1.4.69.dist-info}/WHEEL +0 -0
  27. {ixbrl_viewer-1.4.68.dist-info → ixbrl_viewer-1.4.69.dist-info}/entry_points.txt +0 -0
  28. {ixbrl_viewer-1.4.68.dist-info → ixbrl_viewer-1.4.69.dist-info}/licenses/LICENSE.md +0 -0
  29. {ixbrl_viewer-1.4.68.dist-info → ixbrl_viewer-1.4.69.dist-info}/licenses/NOTICE +0 -0
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ixbrl-viewer
3
- Version: 1.4.68
3
+ Version: 1.4.69
4
4
  Summary: The Arelle iXBRL Viewer allows iXBRL reports to be viewed interactively in a web browser.
5
5
  Author-email: "arelle.org" <support@arelle.org>
6
- License: Apache-2.0
6
+ License-Expression: Apache-2.0
7
7
  Project-URL: Homepage, https://arelle.org/
8
8
  Project-URL: Downloads, https://arelle.org/arelle/pub/
9
9
  Project-URL: Documentation, https://arelle.org/arelle/documentation/
@@ -16,7 +16,6 @@ Platform: any
16
16
  Classifier: Development Status :: 5 - Production/Stable
17
17
  Classifier: Intended Audience :: End Users/Desktop
18
18
  Classifier: Intended Audience :: Developers
19
- Classifier: License :: OSI Approved :: Apache Software License
20
19
  Classifier: Natural Language :: English
21
20
  Classifier: Programming Language :: Python :: 3
22
21
  Classifier: Programming Language :: Python :: 3.9
@@ -1,5 +1,5 @@
1
1
  iXBRLViewerPlugin/__init__.py,sha256=263DtPKBXeTomSI-4SeE7gTX0ak16GiIB9DFOoxBK3k,16839
2
- iXBRLViewerPlugin/_version.py,sha256=Kd9TNep5ObVHkeCsIFDiGJ2HkKOOegq71SMrKWoxBJ4,513
2
+ iXBRLViewerPlugin/_version.py,sha256=RGY9K4dqu3ZQjoMy3PrOoWpI5T5mSbhOnSYlo76P7-E,513
3
3
  iXBRLViewerPlugin/constants.py,sha256=DMyEKzoJZPN36vINiNF9wiP7PPofQg0ZLF0H2CP-ns4,3866
4
4
  iXBRLViewerPlugin/featureConfig.py,sha256=551aLjiGAkoxsgFDMBJT8s3nVaF787kgbRjFumTTsBE,255
5
5
  iXBRLViewerPlugin/iXBRLViewer.py,sha256=7IqbLuapCla5_c-lSM4KiKgSezbioKulJ5pa4ZEPejs,30643
@@ -12,7 +12,7 @@ iXBRLViewerPlugin/viewer/version.js,sha256=7b5si8UmaS7QqALQIP-wJ0I8onKFox8VyaAiU
12
12
  iXBRLViewerPlugin/viewer/webpack.common.js,sha256=hpXufjShXAESQh8Ds7ViJ_tbr8XSb7EdqQLRvyu_mQg,1691
13
13
  iXBRLViewerPlugin/viewer/webpack.dev.js,sha256=R9AwY_TBrg9otvXpDxT1UsGg5eMqi4aXW7C7EIsHzZk,551
14
14
  iXBRLViewerPlugin/viewer/webpack.prod.js,sha256=vfLowWC1EOty0zbq9P-usGaJ3w-JoERpJrYaE9MfoSE,499
15
- iXBRLViewerPlugin/viewer/dist/ixbrlviewer.js,sha256=943HM45kjiTlwY8kr1w8tIhmmmqzs-2kOZJUd0aw-pU,941935
15
+ iXBRLViewerPlugin/viewer/dist/ixbrlviewer.js,sha256=uN0hJpqS29VPpUXwvKh9qeUEnp32kEo6l53ZgCwYJJE,941935
16
16
  iXBRLViewerPlugin/viewer/dist/ixbrlviewer.js.LICENSE.txt,sha256=LtlhXpjEorsiefz-usoFDNTZC_le1KyOKPWgb3RWIq8,1832
17
17
  iXBRLViewerPlugin/viewer/src/data/utr.json,sha256=32ZuovUvTOiCiXnxQH1fyOlgLEbah8DhUInqxZNIjFc,20159
18
18
  iXBRLViewerPlugin/viewer/src/html/fact-details.html,sha256=r3cPuOzcosgBkYl0jfmRUGjYnLgv6Eu0IeTMmUHY4Ak,2863
@@ -208,30 +208,10 @@ iXBRLViewerPlugin/viewer/src/less/text-mixins.less,sha256=pYeQjz6JptSyUTxoVwfNeb
208
208
  iXBRLViewerPlugin/viewer/src/less/validation-report.less,sha256=HWkYEWxny-_zAYrwPXwAXuNCbThMRyomhu6KteUAjEg,351
209
209
  iXBRLViewerPlugin/viewer/src/less/viewer.less,sha256=piLepb_LJUQw0iDfpXtrHI1Wts9L4tbKvAc3ZDtZi-Q,5598
210
210
  iXBRLViewerPlugin/viewer/tools/build-font.js,sha256=Q-Uh0o6Uj2fkKd0zjS7rbVV2mkNydmEWGpkg0uWVir4,818
211
- ixbrl_viewer-1.4.68.dist-info/licenses/LICENSE.md,sha256=FOClHlBMDtwKei0tOJ7pv8WZ_HuQJMNYD1az3NpK73o,16647
212
- ixbrl_viewer-1.4.68.dist-info/licenses/NOTICE,sha256=-SHDY0OY7s4gm4Rdk5AB3nbnUsrdHEHPdJuGFR_vuM4,566
213
- tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
214
- tests/puppeteer/puppeteer_test_run_via_intellij.jpg,sha256=xkFc4lziUkeRxUbhmNSGl1Pte4uQyeMLQY9eiRdHfwQ,80858
215
- tests/puppeteer/framework/core_elements.js,sha256=_46w5G_DxK3bpIOPfcScHqi_nlpewZSQPHxX20ruy5U,3239
216
- tests/puppeteer/framework/utils.js,sha256=egk4UKAtZIrNABtexzZaVLPHQg13sZnyCV61sA6Zl6Y,129
217
- tests/puppeteer/framework/viewer_page.js,sha256=JIQpJ4x2H_s5ua3hSYViTaYuS4mszLNvdp4XNJbAuno,3496
218
- tests/puppeteer/framework/page_objects/doc_frame.js,sha256=PkWK_mRdrWcBAZA0H_ySjrtVxHnQJy5g6ribPwtONns,4196
219
- tests/puppeteer/framework/page_objects/fact_details_panel.js,sha256=nqZWbkhSoYG-h_sVknD0MI-lQwAytDMb_UxOtX3omZg,5151
220
- tests/puppeteer/framework/page_objects/search_panel.js,sha256=lLHX3yYr242A-bFZqgUq6Srp6REsmwO7JddmKE2732Q,2566
221
- tests/puppeteer/framework/page_objects/toolbar.js,sha256=5rtdWMdkxp1n5mTiA4ajBemtf76Ypk4nNtLOscunK5M,779
222
- tests/puppeteer/test_filings/filing_documents_smoke_test.zip,sha256=XThNTiVR23jeej8RAys7s928FitPbiHD6hXfbMdEg-U,21469
223
- tests/puppeteer/test_filings/highlights.zip,sha256=7CM_GjUcPrJdBiSisPmCyuq1rnWRkyRTfvtpNHIagiQ,18766
224
- tests/puppeteer/tests/fact_properties.test.js,sha256=_WsW29v4yh_Q6vLqHJUJyQSkoJgTxBMabBfaKCql1AA,3855
225
- tests/puppeteer/tests/highlight.test.js,sha256=ivTf3MOfDUcNBaukR-CTgNJRbvhXegW-ZH1f4v_1mvc,6130
226
- tests/puppeteer/tests/search.test.js,sha256=N6EDeok_PQct4C8fIFfUeZi-9Wdnc1c1D3YrOJli5pM,3567
227
- tests/puppeteer/tools/generate.sh,sha256=jZ1Jac6KsuRo2nHuA2B9g9mZqr7tLjPJKJAUf0oNArs,524
228
- tests/unit_tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
229
- tests/unit_tests/iXBRLViewerPlugin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
230
- tests/unit_tests/iXBRLViewerPlugin/mock_arelle.py,sha256=fQKJGwceaEVaxvqV9tyuvT6DJB5s1X3-oSMjbFMKlS8,1301
231
- tests/unit_tests/iXBRLViewerPlugin/test_iXBRLViewer.py,sha256=2beDs9kf0wRZFw9NM-dYm4j1zlxRybFj7f1JpwUTttQ,33756
232
- tests/unit_tests/iXBRLViewerPlugin/test_xhtmlserialize.py,sha256=kdrg4i-YXnYAGl9TLWEACPQF0V69OAMXdXLYJwefsH0,12521
233
- ixbrl_viewer-1.4.68.dist-info/METADATA,sha256=5s9CIgTyZD-qlJQ3-Rh3m9d7CGg_Uv5fUFrrFoYpNHQ,18542
234
- ixbrl_viewer-1.4.68.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
235
- ixbrl_viewer-1.4.68.dist-info/entry_points.txt,sha256=2XUzP20WGwxdvnugdBybUBwAB3xf_zvrOR5W_smFz_4,65
236
- ixbrl_viewer-1.4.68.dist-info/top_level.txt,sha256=h8MkrMhC_t2-KbfS1oxJVnFAbn5NZJH8END_BL40mv8,24
237
- ixbrl_viewer-1.4.68.dist-info/RECORD,,
211
+ ixbrl_viewer-1.4.69.dist-info/licenses/LICENSE.md,sha256=FOClHlBMDtwKei0tOJ7pv8WZ_HuQJMNYD1az3NpK73o,16647
212
+ ixbrl_viewer-1.4.69.dist-info/licenses/NOTICE,sha256=-SHDY0OY7s4gm4Rdk5AB3nbnUsrdHEHPdJuGFR_vuM4,566
213
+ ixbrl_viewer-1.4.69.dist-info/METADATA,sha256=QV_to6EJpGR34xChj_bLcqmfCv58RlBPaA3j0ozEEoM,18490
214
+ ixbrl_viewer-1.4.69.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
215
+ ixbrl_viewer-1.4.69.dist-info/entry_points.txt,sha256=2XUzP20WGwxdvnugdBybUBwAB3xf_zvrOR5W_smFz_4,65
216
+ ixbrl_viewer-1.4.69.dist-info/top_level.txt,sha256=iQGm144gaJwCPqPDGQHi8umPFRQAvQShVKDk3JQv3JE,18
217
+ ixbrl_viewer-1.4.69.dist-info/RECORD,,
@@ -1,2 +1 @@
1
1
  iXBRLViewerPlugin
2
- tests
tests/__init__.py DELETED
File without changes
@@ -1,117 +0,0 @@
1
- import { getTextContent } from './utils.js';
2
-
3
- export class Text {
4
- #viewerPage;
5
- #xpathSelector;
6
- #name;
7
-
8
- constructor(viewerPage, xpathSelector, name) {
9
- this.#viewerPage = viewerPage;
10
- this.#xpathSelector = xpathSelector;
11
- this.#name = name;
12
- }
13
-
14
- async assertText(expectedText) {
15
- this.#viewerPage.log(
16
- `Asserting text content of ${this.#name} equals "${expectedText}"`);
17
- const elem = await this.#viewerPage.page.waitForSelector(
18
- 'xpath/' + this.#xpathSelector, { visible: true });
19
- const text = await getTextContent(elem);
20
- expect(text).toEqual(expectedText);
21
- }
22
- }
23
-
24
- export class Button {
25
- #viewerPage;
26
- #xpathSelector;
27
- #name;
28
-
29
- constructor(viewerPage, xpathSelector, name) {
30
- this.#viewerPage = viewerPage;
31
- this.#xpathSelector = xpathSelector;
32
- this.#name = name;
33
- }
34
-
35
- async hover() {
36
- this.#viewerPage.log(`Hovering ${this.#name}`);
37
- const button = await this.getButtonElement();
38
- await button.hover();
39
- }
40
-
41
- async select() {
42
- this.#viewerPage.log(`Select ${this.#name}`);
43
- const button = await this.getButtonElement();
44
- await button.click();
45
- }
46
-
47
- async getButtonElement() {
48
- return await this.#viewerPage.page.waitForSelector(
49
- 'xpath/' + this.#xpathSelector, { visible: true });
50
- }
51
- }
52
-
53
- export class Checkbox {
54
- #viewerPage;
55
- #xpathSelector;
56
- #name;
57
-
58
- constructor(viewerPage, xpathSelector, name) {
59
- this.#viewerPage = viewerPage;
60
- this.#xpathSelector = xpathSelector;
61
- this.#name = name;
62
- }
63
-
64
- async getInput() {
65
- return await this.#viewerPage.page.waitForSelector(
66
- 'xpath/' + this.#xpathSelector, { visible: true });
67
- }
68
-
69
- async isChecked() {
70
- const checkbox = await this.getInput();
71
- return await (await checkbox.getProperty('checked')).jsonValue();
72
- }
73
-
74
- async toggleOff() {
75
- if (await this.isChecked() === true) {
76
- this.#viewerPage.log(`Toggling off ${this.#name}`);
77
- const toggle = await this.getInput();
78
- await toggle.click();
79
- } else {
80
- this.#viewerPage.log(`${this.#name} was already toggled off`);
81
- }
82
- }
83
-
84
- async toggleOn() {
85
- if (await this.isChecked() === false) {
86
- this.#viewerPage.log(`Toggling on ${this.#name}`);
87
- const toggle = await this.getInput();
88
- await toggle.click();
89
- } else {
90
- this.#viewerPage.log(`${this.#name} already toggled on`);
91
- }
92
- }
93
- }
94
-
95
- export class TextInput {
96
- #viewerPage;
97
- #xpathSelector;
98
- #name;
99
-
100
- constructor(viewerPage, xpathSelector, name) {
101
- this.#viewerPage = viewerPage;
102
- this.#xpathSelector = xpathSelector;
103
- this.#name = name;
104
- }
105
-
106
- async enterText(text, pressEnter = false) {
107
- this.#viewerPage.log(`Entering "${text}" into ${this.#name}`);
108
- const input = await this.getInput();
109
- await input.type(text);
110
- await input.press('Enter');
111
- }
112
-
113
- async getInput() {
114
- return await this.#viewerPage.page.waitForSelector(
115
- 'xpath/' + this.#xpathSelector, { visible: true });
116
- }
117
- }
@@ -1,105 +0,0 @@
1
- export class DocFrame {
2
- #viewerPage;
3
-
4
- constructor(viewerPage) {
5
- this.#viewerPage = viewerPage;
6
- }
7
-
8
- async getDocumentIframe() {
9
- const iframe = await this.#viewerPage.page.waitForSelector(
10
- 'xpath/' + '//iframe[@title="iXBRL document view"]');
11
- return iframe.contentFrame();
12
- }
13
-
14
- async getSelectedFact() {
15
- const iframe = await this.getDocumentIframe();
16
- return iframe.waitForSelector(
17
- 'xpath/' + '//*[contains(@class,"ixbrl-selected")]');
18
- }
19
-
20
- // Selects a fact in the document based on name
21
- // Ex: "dei:DocumentType"
22
- async selectFact(name) {
23
- this.#viewerPage.log(`Selecting fact ${name}`);
24
- const iframe = await this.getDocumentIframe();
25
- const fact = await iframe.waitForSelector(
26
- 'xpath/' + `//*[@name="${name}"]`);
27
- return fact.click();
28
- }
29
-
30
- /// Asserts the highlight color matches for the selected document values
31
- async assertHighlights(highlights) {
32
- const contentFrame = await this.getDocumentIframe();
33
- for (const highlight of highlights) {
34
- this.#viewerPage.log(
35
- `Asserting the value "${highlight.docContent}" to be highlighted with ${highlight.property} ${highlight.color}`);
36
- const element = await contentFrame.waitForSelector(
37
- 'xpath/' + highlight.locator);
38
- const style = await contentFrame.evaluate(
39
- (element, property) => getComputedStyle(element)
40
- .getPropertyValue(property), element, highlight.property);
41
- expect(style).toEqual(highlight.color);
42
- }
43
- }
44
- }
45
-
46
- export class Highlight {
47
-
48
- static darkBlue = 'rgb(2, 109, 206)';
49
- static green = 'rgb(190, 234, 143)';
50
- static lightBlue = 'rgb(0, 148, 255)';
51
- static yellow = 'rgb(255, 172, 41)';
52
- static purple = 'rgb(221, 115, 255)';
53
- static propBgColor = 'background-color';
54
- static propOutline = 'outline';
55
- static transparent = 'rgba(0, 0, 0, 0)';
56
-
57
- constructor(color, locator, property, docContent) {
58
- this.color = color;
59
- this.docContent = docContent;
60
- this.locator = locator;
61
- this.property = property;
62
- }
63
-
64
- static fact(docContent, active = true) {
65
- const color = active ? this.green : this.transparent;
66
- const locator = `//*[contains(text(),"${docContent}")]//ancestor::*[contains(@class,"ixbrl-element")]`;
67
- return new Highlight(color, locator, this.propBgColor, docContent);
68
- };
69
-
70
- static factNamespace2(docContent, active = true) {
71
- const color = active ? this.purple : this.transparent;
72
- const locator = `//*[contains(text(),"${docContent}")]//ancestor::*[contains(@class,"ixbrl-element")]`;
73
- return new Highlight(color, locator, this.propBgColor, docContent);
74
- };
75
-
76
- static searchHover(docContent, active = true) {
77
- const color = active
78
- ? `${this.darkBlue} dashed 2px`
79
- : 'rgb(0, 0, 0) none 0px';
80
- const locator = `//*[contains(text(),"${docContent}")]//ancestor::*[contains(@class,"ixbrl-element")]`;
81
- return new Highlight(color, locator, this.propOutline, docContent);
82
- };
83
-
84
- static selectedFact(docContent, active = true) {
85
- const color = active
86
- ? `${this.lightBlue} solid 2px`
87
- : 'rgb(0, 0, 0) none 0px';
88
- const locator = `//*[contains(text(),"${docContent}")]//ancestor::*[contains(@class,"ixbrl-element")]`;
89
- return new Highlight(color, locator, this.propOutline, docContent);
90
- };
91
-
92
- static untaggedDate(docContent, active = true) {
93
- const color = active ? this.yellow : this.transparent;
94
- const locator =
95
- `//*[contains(@class,"review-untagged-date") and contains(text(),"${docContent}")]`;
96
- return new Highlight(color, locator, this.propBgColor, docContent)
97
- }
98
-
99
- static untaggedNumber(docContent, active = true) {
100
- const color = active ? this.purple : this.transparent;
101
- const locator =
102
- `//*[contains(@class,"review-untagged-number") and contains(text(),"${docContent}")]`;
103
- return new Highlight(color, locator, this.propBgColor, docContent);
104
- }
105
- }
@@ -1,112 +0,0 @@
1
- import { Button, Text } from '../core_elements.js';
2
- import { getTextContent } from '../utils.js';
3
-
4
- export class FactDetailsPanel {
5
- #viewerPage;
6
-
7
- constructor(viewerPage) {
8
- this.#viewerPage = viewerPage;
9
-
10
- this.accuracy = new Text(
11
- this.#viewerPage,
12
- '//*[@data-i18n="factDetails.accuracy"]//ancestor::tr//td',
13
- 'Fact Accuracy');
14
- this.concept = new Text(
15
- this.#viewerPage,
16
- '//*[contains(@class, "fact-details")]//*[contains(@class,"std-label")]',
17
- 'Fact Concept');
18
- this.date = new Text(
19
- this.#viewerPage,
20
- '//*[@data-i18n="factDetails.date"]//ancestor::tr//td',
21
- 'Fact Date');
22
- this.duplicateNext = new Button(
23
- this.#viewerPage,
24
- '//*[contains(@class,"duplicates")]//*[contains(@class,"next")]',
25
- 'Duplicate next');
26
- this.duplicateText = new Text(
27
- this.#viewerPage,
28
- '//*[contains(@class,"duplicates")]//*[contains(@class,"text")]',
29
- 'Duplicate Count');
30
- this.factValue = new Text(
31
- this.#viewerPage,
32
- '//*[@data-i18n="factDetails.factValue"]//ancestor::tr//*[contains(concat(" ",@class," "), " value ")]',
33
- 'Fact Value');
34
- this.entity = new Text(
35
- this.#viewerPage,
36
- '//*[@data-i18n="factDetails.entity"]//ancestor::tr//td',
37
- 'Fact Entity');
38
- this.nextFact = new Button(this.#viewerPage,
39
- '//*[contains(@class, "ixbrl-next-tag")]', 'Next Fact');
40
- this.previousFact = new Button(this.#viewerPage,
41
- '//*[contains(@class, "ixbrl-prev-tag")]', 'Previous Fact');
42
- }
43
-
44
- // Asserts the calculation contributors listed in the fact details panel
45
- // under the [sectionTitle]. [expectedCalculation] is a map of concept to
46
- // weight ex: {'cash':'+ '}
47
- async assertCalculation(sectionTitle, expectedCalculations) {
48
- this.#viewerPage.log(`Asserting Calculations for section ${sectionTitle}`);
49
-
50
- // Pull the title elements and assert the section exists
51
- const titleElems = await this.#viewerPage.page.$$('.calculations .title');
52
-
53
- const titles = await Promise.all(titleElems.map(async (e) => await getTextContent(e)));
54
- expect(titles).toContain(sectionTitle)
55
-
56
- // Pull the concepts from the expected section
57
- const calc = await this.#viewerPage.page.evaluate((sectionTitle) => {
58
- const conceptElemsXPath = `
59
- //*[contains(@class,"calculations")]//*[text()="${sectionTitle}"]
60
- //ancestor::*[contains(@class,"card")]//*[contains(@class,"item")]
61
- `;
62
- const conceptElems = document.evaluate(conceptElemsXPath, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
63
-
64
- let calculations = {};
65
- for (let i = 0; i < conceptElems.snapshotLength; i++) {
66
- let elem = conceptElems.snapshotItem(i);
67
- const nameElem = document.evaluate('.//*[contains(@class,"concept-name")]', elem, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
68
- const weightElem = document.evaluate('.//*[contains(@class,"weight")]', elem, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
69
- calculations[nameElem.textContent] = weightElem.textContent;
70
- }
71
-
72
- return calculations;
73
- }, sectionTitle);
74
-
75
- expect(calc).toEqual(expectedCalculations);
76
- }
77
-
78
- async assertFootnotes(expectedFootnotes) {
79
- this.#viewerPage.log('Asserting footnotes');
80
- const conceptElems = await this.#viewerPage.page.$$('.footnotes .block-list-item');
81
- const footnotes = await Promise.all(conceptElems.map(async (e) => await getTextContent(e)));
82
- expect(footnotes).toEqual(expectedFootnotes);
83
- }
84
-
85
- // Returns the width of the fact details panel
86
- async getPanelWidth() {
87
- const inspectorPanel = await this.#viewerPage.page.waitForSelector('#inspector');
88
- const boundingBox = await inspectorPanel.boundingBox();
89
- return boundingBox.width;
90
- }
91
-
92
- // Resizes the panels based on the provided horizontalMovement value.
93
- // positive values will move the panel to the right, negative values will
94
- // move left
95
- async resizePanel(horizontalMovement) {
96
- this.#viewerPage.log('Resizing fact details panel by ' + horizontalMovement + ' pixels');
97
- const resizer = await this.#viewerPage.page
98
- .waitForSelector('#viewer-resize-handle', { visible: true });
99
- const box = await resizer.boundingBox();
100
-
101
- // Start the drag action
102
- const startX = box.x + box.width / 2;
103
- const startY = box.y + box.height / 2;
104
- await this.#viewerPage.page.mouse.move(startX, startY);
105
- await this.#viewerPage.page.mouse.down();
106
-
107
- // Drag horizontally
108
- await this.#viewerPage.page.mouse.move(startX + horizontalMovement, startY, { steps: 10 });
109
- await this.#viewerPage.page.mouse.up();
110
- }
111
-
112
- }
@@ -1,73 +0,0 @@
1
- import { Button, TextInput } from '../core_elements.js';
2
- import { getTextContent } from '../utils.js';
3
-
4
- export class Search {
5
- #viewerPage;
6
-
7
- constructor(viewerPage) {
8
- this.#viewerPage = viewerPage;
9
- this.filterToggle = new Button(this.#viewerPage,
10
- '//*[contains(@class,"filter-toggle")]', 'Filter Toggle');
11
- this.reset = new Button(this.#viewerPage,
12
- '//*[contains(@data-i18n,"inspector.reset")]', 'Reset');
13
- this.searchButton = new Button(this.#viewerPage,
14
- '//*[contains(@class,"search-button")]', 'Search');
15
- this.searchInput = new TextInput(this.#viewerPage,
16
- '//*[@id="ixbrl-search"]', 'Search Input');
17
- }
18
-
19
- async getSearchResults() {
20
- const elements = await this.#viewerPage.page.$$('.search-results .fact-list-item .title');
21
- return Promise.all(elements.map(async (e) => {
22
- return getTextContent(e);
23
- }));
24
- }
25
-
26
- async assertSearchResultsContain(concepts) {
27
- this.#viewerPage.log(`Asserting search results contain ${concepts}`);
28
- const results = await this.getSearchResults();
29
- for (const concept of concepts) {
30
- expect(results).toContain(concept);
31
- }
32
- }
33
-
34
- async assertSearchResultsDoNotContain(concepts) {
35
- this.#viewerPage.log(
36
- `Asserting search results do not contain ${concepts}`);
37
- const results = await this.getSearchResults();
38
- for (const concept of concepts) {
39
- expect(results).not.toContain(concept);
40
- }
41
- }
42
-
43
- async filterConceptType(option) {
44
- const dropdown = await this.#viewerPage.page
45
- .waitForSelector('#search-filter-concept-type');
46
- await dropdown.select(option);
47
- }
48
-
49
- async filterPeriod(option) {
50
- const dropdown = await this.#viewerPage.page
51
- .waitForSelector('#search-filter-period select');
52
- await dropdown.select(option);
53
- }
54
-
55
- getSearchResultCard(conceptName) {
56
- return new SearchResultCard(this.#viewerPage, conceptName);
57
- }
58
- }
59
-
60
- export class SearchResultCard {
61
- #viewerPage;
62
-
63
- constructor(viewerPage, conceptName) {
64
- this.conceptName = conceptName;
65
- this.#viewerPage = viewerPage;
66
- this.locator = `//*[contains(@class,"title")
67
- and contains(text(),"${this.conceptName}")]
68
- //ancestor::*[contains(@class,"fact-list-item")]`;
69
- this.selectButton = new Button(this.#viewerPage,
70
- `${this.locator}//*[contains(@class,"select-icon")]`,
71
- 'Select Button');
72
- }
73
- }
@@ -1,18 +0,0 @@
1
- import { Checkbox } from '../core_elements.js';
2
-
3
- export class Toolbar {
4
- #viewerPage;
5
-
6
- constructor(viewerPage) {
7
- this.#viewerPage = viewerPage;
8
- this.xbrlElementHighlight = new Checkbox(this.#viewerPage,
9
- '//*[contains(@class,"top-bar-controls")]//*[contains(text(),"XBRL Elements")]//input',
10
- 'XBRL Element Highlight');
11
- this.unTaggedDateHighlight = new Checkbox(this.#viewerPage,
12
- '//*[contains(@class,"top-bar-controls")]//*[contains(text(),"Untagged Dates")]//input',
13
- 'Untagged Dates');
14
- this.unTaggedNumberHighlight = new Checkbox(this.#viewerPage,
15
- '//*[contains(@class,"top-bar-controls")]//*[contains(text(),"Untagged Numbers")]//input',
16
- 'Untagged Numbers');
17
- }
18
- }
@@ -1,3 +0,0 @@
1
- export async function getTextContent(elementHandle) {
2
- return (await elementHandle.getProperty('textContent')).jsonValue();
3
- }
@@ -1,103 +0,0 @@
1
- import fs from 'fs';
2
- import puppeteer from 'puppeteer';
3
- import { DocFrame } from './page_objects/doc_frame.js';
4
- import { FactDetailsPanel } from './page_objects/fact_details_panel.js';
5
- import { PuppeteerScreenRecorder } from 'puppeteer-screen-recorder';
6
- import { Search } from './page_objects/search_panel.js';
7
- import { Toolbar } from './page_objects/toolbar.js';
8
-
9
- export class ViewerPage {
10
- browser;
11
- page;
12
- docFrame;
13
- factDetailsPanel;
14
- search;
15
- toolbar;
16
-
17
- #artifactDirectory = './tests/puppeteer/artifacts';
18
- #cleanedTestName = expect.getState()
19
- .currentTestName
20
- .replaceAll(/[^a-zA-Z0-9-]/g, '_');
21
- #isCi = process.env.CI === 'true';
22
- #logMsgs = [];
23
- #recorder;
24
-
25
- async buildPage() {
26
- // Launch the browser
27
- this.browser = await puppeteer.launch({
28
- headless: this.#isCi ? 'new' : false,
29
- args: [`--window-size=1440,900`],
30
- defaultViewport: { width: 1440, height: 821 },
31
- });
32
- this.page = await this.browser.newPage();
33
- this.docFrame = new DocFrame(this);
34
- this.factDetailsPanel = new FactDetailsPanel(this);
35
- this.search = new Search(this);
36
- this.toolbar = new Toolbar(this);
37
- this.#recorder = new PuppeteerScreenRecorder(this.page);
38
-
39
- // Set up the video recording
40
- const videoDir = `${this.#artifactDirectory}/video`;
41
- const videoPath = `${videoDir}/${this.#cleanedTestName}.mp4`;
42
- await this.#createDirectory(videoDir);
43
- await this.#recorder.start(videoPath);
44
-
45
- this.streamLogsToFile(
46
- `${this.#artifactDirectory}/${this.#cleanedTestName}_chrome_debug.log`);
47
- }
48
-
49
- log(message) {
50
- this.#logMsgs.push(message);
51
- }
52
-
53
- async navigateToViewer(filingZipName, args = '') {
54
-
55
- const filingName = filingZipName.replace('.zip', '');
56
- const url = `http://localhost:8080/tests/puppeteer/artifacts/generated_output/${filingName}.htm${args}`;
57
- this.log(`Navigating to ${url}`);
58
- await this.page.goto(url, { waitUntil: 'networkidle0' });
59
- await this.page.waitForSelector(
60
- 'xpath/' + '//*[contains(@class, "loading")]',
61
- { visible: false, hidden: true });
62
- }
63
-
64
- async tearDown() {
65
- console.log(this.#logMsgs.join('\n'));
66
- await this.#recorder.stop();
67
- await this.browser.close();
68
- }
69
-
70
- async #createDirectory(path) {
71
- if (!fs.existsSync(path)) {
72
- fs.mkdirSync(path, { recursive: true });
73
- }
74
- }
75
-
76
- streamLogsToFile(filename) {
77
- const append = (content) => fs.appendFile(filename, `${content}\n`,
78
- function(err) {
79
- if (err) throw err;
80
- });
81
-
82
- // Delete the file if it already exists
83
- fs.rmSync(filename, { force: true });
84
-
85
- // Pipe the log messages to the file
86
- this.page.on('console', msg => append(
87
- `${msg.type().substr(0, 3).toUpperCase()} ${msg.text()}`))
88
- .on('pageerror', function(err) {
89
- let value = err.toString();
90
- append(value);
91
- })
92
- .on('response', response => append(
93
- `${response.status()} ${response.url()}`))
94
- .on('requestfailed', request => append(
95
- `${request.failure().errorText} ${request.url()}`));
96
- }
97
-
98
- async waitMilliseconds(milliseconds) {
99
- return new Promise(function(resolve) {
100
- setTimeout(resolve, milliseconds);
101
- });
102
- }
103
- }
Binary file