1 |
|
2 |
|
3 | import { getDiffableHTML, isDiffOptions } from './get-diffable-html.js';
|
4 | import { getOuterHtml, getCleanedShadowDom, snapshotPath } from './src/utils.js';
|
5 |
|
6 |
|
7 |
|
8 | function disambiguateArgs(...args) {
|
9 | switch (args.length) {
|
10 |
|
11 | case 2: {
|
12 | const [message, options] = args;
|
13 | return { message, options };
|
14 | }
|
15 |
|
16 |
|
17 |
|
18 | case 1: {
|
19 | const [first] = args;
|
20 | return isDiffOptions(first) ? { options: first } : { message: first };
|
21 | }
|
22 |
|
23 | default:
|
24 | return {};
|
25 | }
|
26 | }
|
27 |
|
28 |
|
29 |
|
30 |
|
31 | export const chaiDomDiff = (chai, utils) => {
|
32 | |
33 |
|
34 |
|
35 | chai.Assertion.addProperty('lightDom', function lightDom() {
|
36 | new chai.Assertion(this._obj.nodeType).to.equal(1);
|
37 | utils.flag(this, 'lightDom', true);
|
38 | });
|
39 |
|
40 | |
41 |
|
42 |
|
43 | chai.Assertion.addProperty('shadowDom', function shadowDom() {
|
44 | new chai.Assertion(this._obj.nodeType).to.equal(1);
|
45 | utils.flag(this, 'shadowDom', true);
|
46 | });
|
47 |
|
48 | |
49 |
|
50 |
|
51 | chai.Assertion.addProperty('dom', function dom() {
|
52 | new chai.Assertion(this._obj.nodeType).to.equal(1);
|
53 | utils.flag(this, 'dom', true);
|
54 | });
|
55 |
|
56 | const getDomHtml = el => getOuterHtml(el);
|
57 | const getLightDomHtml = el => el.innerHTML;
|
58 | const getShadowDomHtml = el => getCleanedShadowDom(el);
|
59 |
|
60 | |
61 |
|
62 |
|
63 |
|
64 |
|
65 |
|
66 |
|
67 | const assertHtmlEquals = (actual, expected, negate, ...rest) => {
|
68 | const { message, options } = disambiguateArgs(...rest);
|
69 |
|
70 | const assertion = new chai.Assertion(getDiffableHTML(actual, options), message);
|
71 | const expectedDiffableHTML = getDiffableHTML(expected, options);
|
72 |
|
73 | if (negate) {
|
74 | assertion.not.equal(expectedDiffableHTML, message);
|
75 | } else {
|
76 | assertion.equal(expectedDiffableHTML, message);
|
77 | }
|
78 | };
|
79 |
|
80 |
|
81 | const domEquals = _super =>
|
82 | |
83 |
|
84 |
|
85 | function handleDom(value, ...args) {
|
86 | if (
|
87 | utils.flag(this, 'lightDom') ||
|
88 | utils.flag(this, 'shadowDom') ||
|
89 | utils.flag(this, 'dom')
|
90 | ) {
|
91 | let html;
|
92 | if (utils.flag(this, 'lightDom')) {
|
93 | html = getLightDomHtml(this._obj);
|
94 | } else if (utils.flag(this, 'shadowDom')) {
|
95 | html = getShadowDomHtml(this._obj);
|
96 | } else {
|
97 | html = getDomHtml(this._obj);
|
98 | }
|
99 |
|
100 | assertHtmlEquals(html, value, utils.flag(this, 'negate'), args[0]);
|
101 | } else {
|
102 | _super.apply(this, [value, ...args]);
|
103 | }
|
104 | };
|
105 |
|
106 | chai.Assertion.overwriteMethod('equals', domEquals);
|
107 | chai.Assertion.overwriteMethod('equal', domEquals);
|
108 | chai.Assertion.overwriteMethod('eq', domEquals);
|
109 |
|
110 | const context = window.__mocha_context__;
|
111 | const snapshotState = window.__snapshot__;
|
112 |
|
113 | |
114 |
|
115 |
|
116 |
|
117 |
|
118 |
|
119 |
|
120 | function assertHtmlEqualsSnapshot(actual, negate, ...rest) {
|
121 | const { message, options } = disambiguateArgs(...rest);
|
122 | const { index } = context;
|
123 | context.index += 1;
|
124 | let path;
|
125 |
|
126 | const html = getDiffableHTML(actual, options);
|
127 |
|
128 | if (context.runnable.type === 'hook') {
|
129 | path = snapshotPath(context.runnable.ctx.currentTest);
|
130 | } else {
|
131 | path = snapshotPath(context.runnable);
|
132 | }
|
133 |
|
134 | if (snapshotState.update) {
|
135 | snapshotState.set(path, index, html, 'html');
|
136 | } else {
|
137 | const snapshot = snapshotState.get(path, index);
|
138 |
|
139 | if (!snapshot) {
|
140 | snapshotState.set(path, index, html, 'html');
|
141 | } else {
|
142 | const isMatch = snapshotState.match(html, getDiffableHTML(snapshot.code, options));
|
143 | if ((isMatch && negate) || (!isMatch && !negate)) {
|
144 |
|
145 | throw new chai.AssertionError(
|
146 | message || `Received value does not match stored snapshot ${index}`,
|
147 | {
|
148 | actual: html,
|
149 | expected: snapshot.code,
|
150 | showDiff: true,
|
151 | },
|
152 | chai.util.flag(this, 'ssfi'),
|
153 | );
|
154 | }
|
155 | }
|
156 | }
|
157 | }
|
158 |
|
159 | |
160 |
|
161 |
|
162 |
|
163 | function equalSnapshot(options) {
|
164 | const el = chai.util.flag(this, 'object');
|
165 | let html;
|
166 | if (utils.flag(this, 'shadowDom')) {
|
167 | html = getShadowDomHtml(el);
|
168 | } else if (utils.flag(this, 'lightDom')) {
|
169 | html = getLightDomHtml(el);
|
170 | } else {
|
171 | html = el;
|
172 | }
|
173 | return assertHtmlEqualsSnapshot.call(this, html, utils.flag(this, 'negate'), options);
|
174 | }
|
175 |
|
176 | utils.addMethod(chai.Assertion.prototype, 'equalSnapshot', equalSnapshot);
|
177 | utils.addMethod(chai.Assertion.prototype, 'notEqualSnapshot', equalSnapshot);
|
178 |
|
179 | utils.addMethod(chai.assert, 'equalSnapshot', assertHtmlEqualsSnapshot);
|
180 | utils.addMethod(chai.assert, 'notEqualSnapshot', assertHtmlEqualsSnapshot);
|
181 |
|
182 |
|
183 | chai.assert.dom = {
|
184 | equal(actualEl, expectedHTML, ...rest) {
|
185 | const negate = false;
|
186 | return assertHtmlEquals.call(this, getDomHtml(actualEl), expectedHTML, negate, ...rest);
|
187 | },
|
188 | notEqual(actualEl, expectedHTML, ...rest) {
|
189 | const negate = true;
|
190 | return assertHtmlEquals.call(this, getDomHtml(actualEl), expectedHTML, negate, ...rest);
|
191 | },
|
192 | equalSnapshot(actualEl, ...rest) {
|
193 | const negate = false;
|
194 | return assertHtmlEqualsSnapshot.call(this, actualEl, negate, ...rest);
|
195 | },
|
196 | notEqualSnapshot(actualEl, ...rest) {
|
197 | const negate = true;
|
198 | return assertHtmlEqualsSnapshot.call(this, actualEl, negate, ...rest);
|
199 | },
|
200 | };
|
201 |
|
202 |
|
203 | chai.assert.lightDom = {
|
204 | equal(actualEl, expectedHTML, ...rest) {
|
205 | const negate = false;
|
206 | return assertHtmlEquals.call(this, getLightDomHtml(actualEl), expectedHTML, negate, ...rest);
|
207 | },
|
208 | notEqual(actualEl, expectedHTML, ...rest) {
|
209 | const negate = true;
|
210 | return assertHtmlEquals.call(this, getLightDomHtml(actualEl), expectedHTML, negate, ...rest);
|
211 | },
|
212 | equalSnapshot(actualEl, ...rest) {
|
213 | const negate = false;
|
214 | return assertHtmlEqualsSnapshot.call(this, getLightDomHtml(actualEl), negate, ...rest);
|
215 | },
|
216 | notEqualSnapshot(actualEl, ...rest) {
|
217 | const negate = true;
|
218 | return assertHtmlEqualsSnapshot.call(this, getLightDomHtml(actualEl), negate, ...rest);
|
219 | },
|
220 | };
|
221 |
|
222 |
|
223 | chai.assert.shadowDom = {
|
224 | equal(actualEl, expectedHTML, ...rest) {
|
225 | const negate = false;
|
226 | return assertHtmlEquals.call(this, getShadowDomHtml(actualEl), expectedHTML, negate, ...rest);
|
227 | },
|
228 | notEqual(actualEl, expectedHTML, ...rest) {
|
229 | const negate = true;
|
230 | return assertHtmlEquals.call(this, getShadowDomHtml(actualEl), expectedHTML, negate, ...rest);
|
231 | },
|
232 | equalSnapshot(actualEl, ...rest) {
|
233 | const negate = false;
|
234 | return assertHtmlEqualsSnapshot.call(this, getShadowDomHtml(actualEl), negate, ...rest);
|
235 | },
|
236 | notEqualSnapshot(actualEl, ...rest) {
|
237 | const negate = true;
|
238 | return assertHtmlEqualsSnapshot.call(this, getShadowDomHtml(actualEl), negate, ...rest);
|
239 | },
|
240 | };
|
241 | };
|