Skip to content

Commit a986552

Browse files
committed
Dedupe across instances
1 parent 9399590 commit a986552

24 files changed

Lines changed: 392 additions & 259 deletions

__tests__/html2/provider/InjectStylesElementsComposer/changeNonce.html

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
const {
1717
testHelpers: { createDirectLineEmulator },
1818
WebChat: {
19-
Components: { ThemeProvider }
19+
Components: { ThemeProvider },
20+
internal: { InjectStyleElementsComposer }
2021
}
2122
} = window;
2223

@@ -39,34 +40,50 @@
3940
return false;
4041
};
4142

42-
const render = ({ elements, nonce, stylesRoot }) =>
43+
const render = ({ nonce, styleElements, stylesRoot }) =>
4344
new Promise(resolve =>
4445
ReactDOM.render(
45-
<ThemeProvider styles={elements} nonce={nonce} styleOptions={stylesRoot ? { stylesRoot } : {}} />,
46+
<ThemeProvider styleOptions={stylesRoot ? { stylesRoot } : {}}>
47+
<InjectStyleElementsComposer nonce={nonce} styleElements={styleElements} />
48+
</ThemeProvider>,
4649
document.getElementById('webchat'),
4750
resolve
4851
)
4952
);
5053

5154
const styleElement = createStyle('main { background-color: Red!important; }');
5255

53-
await render({ elements: [styleElement], nonce: '1' });
56+
// WHEN: Inject with nonce of "1".
57+
await render({ nonce: '1', styleElements: [styleElement] });
58+
59+
// THEN: Should render in red color.
5460
await host.snapshot('local');
5561

62+
// THEN: The cloned/injected style should be the last child.
63+
expect(document.head.lastChild).toHaveProperty('textContent', styleElement.textContent);
64+
65+
// THEN: Only one <style> element is added.
5666
const allInjectedStyles1 = document.head.querySelectorAll('style[data-testid="style"]');
5767

5868
expect(allInjectedStyles1).toHaveLength(1);
59-
expect(allInjectedStyles1[0]).toBe(styleElement);
69+
expect(allInjectedStyles1[0]).toHaveProperty('textContent', styleElement.textContent);
70+
expect(allInjectedStyles1[0].getAttribute('nonce')).toBe('1');
6071

61-
await render({ elements: [styleElement], nonce: '2' });
72+
// WHEN: Inject with nonce of "2".
73+
await render({ nonce: '2', styleElements: [styleElement] });
6274

63-
// No color should be applied as nonce don't match.
75+
// THEN: No color should be applied as nonce don't match.
6476
await host.snapshot('local');
6577

78+
// THEN: The cloned/injected style should be the last child.
79+
expect(document.head.lastChild).toHaveProperty('textContent', styleElement.textContent);
80+
81+
// THEN: Only one <style> element is added.
6682
const allInjectedStyles2 = document.head.querySelectorAll('style[data-testid="style"]');
6783

6884
expect(allInjectedStyles2).toHaveLength(1);
69-
expect(allInjectedStyles2[0]).toBe(styleElement);
85+
expect(allInjectedStyles2[0]).toHaveProperty('textContent', styleElement.textContent);
86+
expect(allInjectedStyles2[0].getAttribute('nonce')).toBe('2');
7087
},
7188
{ ignoreErrors: 'violate the following Content Security Policy directive' }
7289
);

__tests__/html2/provider/InjectStylesElementsComposer/changeRoot.html

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
const {
1616
testHelpers: { createDirectLineEmulator },
1717
WebChat: {
18-
Components: { ThemeProvider }
18+
Components: { ThemeProvider },
19+
internal: { InjectStyleElementsComposer }
1920
}
2021
} = window;
2122

@@ -37,28 +38,48 @@
3738
return false;
3839
};
3940

40-
const render = ({ elements, nonce, stylesRoot }) =>
41+
const render = ({ nonce, styleElements, stylesRoot }) =>
4142
new Promise(resolve =>
4243
ReactDOM.render(
43-
<ThemeProvider styles={elements} nonce={nonce} styleOptions={stylesRoot ? { stylesRoot } : {}} />,
44+
<ThemeProvider styleOptions={stylesRoot ? { stylesRoot } : {}}>
45+
<InjectStyleElementsComposer nonce={nonce} styleElements={styleElements} />
46+
</ThemeProvider>,
4447
document.getElementById('webchat'),
4548
resolve
4649
)
4750
);
4851

4952
const styleElement = createStyle('main { background-color: Red!important; }');
5053

51-
await render({ elements: [styleElement] });
54+
// WHEN: Inject into default (document.head).
55+
await render({ styleElements: [styleElement] });
56+
57+
// THEN: Should render red.
5258
await host.snapshot('local');
5359

54-
expect([...document.head.querySelectorAll('style[data-testid="style"]')]).toEqual([styleElement]);
55-
expect([...document.body.querySelectorAll('style[data-testid="style"]')]).toEqual([]);
60+
// THEN: Should inject into document.head.
61+
const styleElementsInHead = document.head.querySelectorAll('style[data-testid="style"]');
62+
63+
expect(styleElementsInHead).toHaveLength(1);
64+
expect(styleElementsInHead[0]).toHaveProperty('textContent', styleElement.textContent);
65+
66+
// THEN: Should not inject into document.body.
67+
expect(document.body.querySelectorAll('style[data-testid="style"]')).toHaveLength(0);
5668

57-
await render({ elements: [styleElement], stylesRoot: document.body });
69+
// WHEN: Inject into document.body.
70+
await render({ styleElements: [styleElement], stylesRoot: document.body });
71+
72+
// THEN: Should render red.
5873
await host.snapshot('local');
5974

60-
expect([...document.head.querySelectorAll('style[data-testid="style"]')]).toEqual([]);
61-
expect([...document.body.querySelectorAll('style[data-testid="style"]')]).toEqual([styleElement]);
75+
// THEN: Should inject into document.body.
76+
const styleElementsInBody = document.body.querySelectorAll('style[data-testid="style"]');
77+
78+
expect(styleElementsInBody).toHaveLength(1);
79+
expect(styleElementsInBody[0]).toHaveProperty('textContent', styleElement.textContent);
80+
81+
// THEN: Should not inject into document.head.
82+
expect(document.head.querySelectorAll('style[data-testid="style"]')).toHaveLength(0);
6283
});
6384
</script>
6485
</body>

__tests__/html2/provider/InjectStylesElementsComposer/dupeElement.html

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
const {
1616
testHelpers: { createDirectLineEmulator },
1717
WebChat: {
18-
Components: { ThemeProvider }
18+
Components: { ThemeProvider },
19+
internal: { InjectStyleElementsComposer }
1920
}
2021
} = window;
2122

@@ -37,53 +38,55 @@
3738
return false;
3839
};
3940

40-
const render = ({ elements, nonce, stylesRoot }) =>
41+
const render = ({ nonce, styleElements, stylesRoot }) =>
4142
new Promise(resolve =>
4243
ReactDOM.render(
43-
<ThemeProvider styles={elements} nonce={nonce} styleOptions={stylesRoot ? { stylesRoot } : {}} />,
44+
<ThemeProvider styleOptions={stylesRoot ? { stylesRoot } : {}}>
45+
<InjectStyleElementsComposer nonce={nonce} styleElements={styleElements} />
46+
</ThemeProvider>,
4447
document.getElementById('webchat'),
4548
resolve
4649
)
4750
);
4851

4952
const styleElement = createStyle('main { background-color: Red!important; }');
5053

51-
await render({ elements: [styleElement, styleElement] });
54+
await render({ styleElements: [styleElement, styleElement] });
55+
56+
// THEN: Should render in red.
5257
await host.snapshot('local');
5358

54-
const allInjectedStyles1 = document.head.querySelectorAll(
55-
'style[data-testid="style"]'
56-
);
59+
const allInjectedStyles1 = document.head.querySelectorAll('style[data-testid="style"]');
5760

5861
expect(allInjectedStyles1).toHaveLength(1);
59-
expect(allInjectedStyles1[0]).toBe(styleElement);
62+
expect(allInjectedStyles1[0]).toHaveProperty('textContent', styleElement.textContent);
63+
64+
await render({ styleElements: [styleElement, styleElement] });
6065

61-
await render({ elements: [styleElement, styleElement] });
66+
// THEN: Should render in red.
6267
await host.snapshot('local');
6368

64-
const allInjectedStyles2 = document.head.querySelectorAll(
65-
'style[data-testid="style"]'
66-
);
69+
const allInjectedStyles2 = document.head.querySelectorAll('style[data-testid="style"]');
6770

6871
expect(allInjectedStyles2).toHaveLength(1);
69-
expect(allInjectedStyles2[0]).toBe(styleElement);
72+
expect(allInjectedStyles2[0]).toHaveProperty('textContent', styleElement.textContent);
7073

71-
await render({ elements: [styleElement] });
74+
await render({ styleElements: [styleElement] });
75+
76+
// THEN: Should render in red.
7277
await host.snapshot('local');
7378

74-
const allInjectedStyles3 = document.head.querySelectorAll(
75-
'style[data-testid="style"]'
76-
);
79+
const allInjectedStyles3 = document.head.querySelectorAll('style[data-testid="style"]');
7780

7881
expect(allInjectedStyles3).toHaveLength(1);
79-
expect(allInjectedStyles3[0]).toBe(styleElement);
82+
expect(allInjectedStyles3[0]).toHaveProperty('textContent', styleElement.textContent);
83+
84+
await render({ styleElements: [] });
8085

81-
await render({ elements: [] });
86+
// THEN: Should render in white because all stylesheet should have been removed.
8287
await host.snapshot('local');
8388

84-
const allInjectedStyles4 = document.head.querySelectorAll(
85-
'style[data-testid="style"]'
86-
);
89+
const allInjectedStyles4 = document.head.querySelectorAll('style[data-testid="style"]');
8790

8891
expect(allInjectedStyles4).toHaveLength(0);
8992
});

__tests__/html2/provider/InjectStylesElementsComposer/dupeElement.withParent.html

Lines changed: 0 additions & 93 deletions
This file was deleted.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

__tests__/html2/provider/InjectStylesElementsComposer/link.html

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
const {
1616
testHelpers: { createDirectLineEmulator },
1717
WebChat: {
18-
Components: { ThemeProvider }
18+
Components: { ThemeProvider },
19+
internal: { InjectStyleElementsComposer }
1920
}
2021
} = window;
2122

@@ -39,10 +40,12 @@
3940
return false;
4041
};
4142

42-
const render = ({ elements, nonce, stylesRoot }) =>
43+
const render = ({ nonce, styleElements, stylesRoot }) =>
4344
new Promise(resolve =>
4445
ReactDOM.render(
45-
<ThemeProvider styles={elements} nonce={nonce} styleOptions={stylesRoot ? { stylesRoot } : {}} />,
46+
<ThemeProvider styleOptions={stylesRoot ? { stylesRoot } : {}}>
47+
<InjectStyleElementsComposer nonce={nonce} styleElements={styleElements} />
48+
</ThemeProvider>,
4649
document.getElementById('webchat'),
4750
resolve
4851
)
@@ -52,32 +55,38 @@
5255
const linkStyleSheetElement2 = createLinkStyleSheet('./css/2.css');
5356
const linkStyleSheetElement3 = createLinkStyleSheet('./css/3.css');
5457

55-
await render({ elements: [linkStyleSheetElement1] });
58+
await render({ styleElements: [linkStyleSheetElement1] });
59+
60+
// THEN: Should render in red.
5661
await host.snapshot('local');
5762

5863
const allInjectedStyles1 = document.head.querySelectorAll('link[data-testid="style"]');
5964

6065
expect(allInjectedStyles1).toHaveLength(1);
61-
expect(allInjectedStyles1[0]).toBe(linkStyleSheetElement1);
66+
expect(allInjectedStyles1[0]).toHaveProperty('href', linkStyleSheetElement1.href);
67+
68+
await render({ styleElements: [linkStyleSheetElement1, linkStyleSheetElement2] });
6269

63-
await render({ elements: [linkStyleSheetElement1, linkStyleSheetElement2] });
70+
// THEN: Should render in orange (2.css is preferred over others).
6471
await host.snapshot('local');
6572

6673
const allInjectedStyles2 = document.head.querySelectorAll('link[data-testid="style"]');
6774

6875
expect(allInjectedStyles2).toHaveLength(2);
69-
expect(allInjectedStyles2[0]).toBe(linkStyleSheetElement1);
70-
expect(allInjectedStyles2[1]).toBe(linkStyleSheetElement2);
76+
expect(allInjectedStyles2[0]).toHaveProperty('href', linkStyleSheetElement1.href);
77+
expect(allInjectedStyles2[1]).toHaveProperty('href', linkStyleSheetElement2.href);
78+
79+
await render({ styleElements: [linkStyleSheetElement1, linkStyleSheetElement2, linkStyleSheetElement3] });
7180

72-
await render({ elements: [linkStyleSheetElement1, linkStyleSheetElement2, linkStyleSheetElement3] });
81+
// THEN: Should render in yellow (3.css is preferred over others).
7382
await host.snapshot('local');
7483

7584
const allInjectedStyles3 = document.head.querySelectorAll('link[data-testid="style"]');
7685

7786
expect(allInjectedStyles3).toHaveLength(3);
78-
expect(allInjectedStyles3[0]).toBe(linkStyleSheetElement1);
79-
expect(allInjectedStyles3[1]).toBe(linkStyleSheetElement2);
80-
expect(allInjectedStyles3[2]).toBe(linkStyleSheetElement3);
87+
expect(allInjectedStyles3[0]).toHaveProperty('href', linkStyleSheetElement1.href);
88+
expect(allInjectedStyles3[1]).toHaveProperty('href', linkStyleSheetElement2.href);
89+
expect(allInjectedStyles3[2]).toHaveProperty('href', linkStyleSheetElement3.href);
8190
});
8291
</script>
8392
</body>

0 commit comments

Comments
 (0)