@nyaruka/temba-components 0.25.2 → 0.26.0
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/CHANGELOG.md +11 -0
- package/demo/index.html +1 -0
- package/dist/b5b37a88.js +1 -0
- package/dist/index.js +1 -356
- package/dist/sw.js +1 -1
- package/dist/sw.js.map +1 -1
- package/dist/templates/components-body.html +1 -1
- package/dist/templates/components-head.html +1 -1
- package/out-tsc/src/aliaseditor/AliasEditor.js +1 -2
- package/out-tsc/src/aliaseditor/AliasEditor.js.map +1 -1
- package/out-tsc/src/list/TembaMenu.js +76 -22
- package/out-tsc/src/list/TembaMenu.js.map +1 -1
- package/out-tsc/src/vectoricon/VectorIcon.js +6 -1
- package/out-tsc/src/vectoricon/VectorIcon.js.map +1 -1
- package/package.json +2 -2
- package/src/aliaseditor/AliasEditor.ts +1 -2
- package/src/list/TembaMenu.ts +82 -22
- package/src/vectoricon/VectorIcon.ts +6 -1
- package/web-test-runner.config.mjs +127 -117
- package/dist/56e0e480.js +0 -356
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import { puppeteerLauncher } from '@web/test-runner-puppeteer';
|
|
2
|
-
import fs from
|
|
3
|
-
import * as path from
|
|
4
|
-
import * as pngs from
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import * as pngs from 'pngjs';
|
|
5
5
|
import dynamicpixelmatch from 'dynamicpixelmatch';
|
|
6
6
|
import pixelmatch from 'pixelmatch';
|
|
7
7
|
import sizeOf from 'image-size';
|
|
8
8
|
|
|
9
|
-
import rimraf from
|
|
9
|
+
import rimraf from 'rimraf';
|
|
10
10
|
|
|
11
11
|
const SCREENSHOTS = 'screenshots';
|
|
12
12
|
const DIFF = 'diff';
|
|
13
|
-
const TEST =
|
|
14
|
-
const TRUTH =
|
|
13
|
+
const TEST = 'test';
|
|
14
|
+
const TRUTH = 'truth';
|
|
15
15
|
|
|
16
16
|
const PNG = pngs.PNG;
|
|
17
17
|
|
|
18
|
-
const fileExists =
|
|
18
|
+
const fileExists = filename => {
|
|
19
19
|
return new Promise((resolve, reject) => {
|
|
20
|
-
fs.access(filename, fs.F_OK,
|
|
20
|
+
fs.access(filename, fs.F_OK, err => {
|
|
21
21
|
if (err) {
|
|
22
22
|
resolve(false);
|
|
23
23
|
}
|
|
@@ -28,35 +28,31 @@ const fileExists = (filename) => {
|
|
|
28
28
|
|
|
29
29
|
const ensureExists = function (mydir) {
|
|
30
30
|
return new Promise((resolve, reject) => {
|
|
31
|
-
fs.mkdir(mydir, {recursive: true }, function (err) {
|
|
31
|
+
fs.mkdir(mydir, { recursive: true }, function (err) {
|
|
32
32
|
if (err) {
|
|
33
|
-
if (err.code ==
|
|
34
|
-
resolve(
|
|
33
|
+
if (err.code == 'EEXIST')
|
|
34
|
+
resolve('ignore the error if the folder already exists');
|
|
35
35
|
else reject(err); // something else went wrong
|
|
36
36
|
}
|
|
37
|
-
resolve(
|
|
37
|
+
resolve('path created');
|
|
38
38
|
});
|
|
39
39
|
});
|
|
40
40
|
};
|
|
41
41
|
|
|
42
|
-
|
|
43
42
|
const getPath = async (type, filename) => {
|
|
44
|
-
const file = path.resolve(SCREENSHOTS, type, filename)
|
|
43
|
+
const file = path.resolve(SCREENSHOTS, type, filename);
|
|
45
44
|
|
|
46
45
|
// make sure our directory exists
|
|
47
46
|
const parts = filename.split(path.sep);
|
|
48
47
|
let pngdir = parts.slice(0, parts.length - 1);
|
|
49
48
|
await ensureExists(path.resolve(SCREENSHOTS, type, ...pngdir));
|
|
50
|
-
|
|
51
|
-
return file;
|
|
52
|
-
}
|
|
53
49
|
|
|
50
|
+
return file;
|
|
51
|
+
};
|
|
54
52
|
|
|
55
53
|
const checkScreenshot = async (filename, excluded, threshold) => {
|
|
56
|
-
|
|
57
54
|
return new Promise(async (resolve, reject) => {
|
|
58
55
|
const doneReading = async () => {
|
|
59
|
-
|
|
60
56
|
// Wait until both files are read.
|
|
61
57
|
if (++filesRead < 2) return;
|
|
62
58
|
|
|
@@ -64,20 +60,25 @@ const checkScreenshot = async (filename, excluded, threshold) => {
|
|
|
64
60
|
if (img1.width != img2.width || img1.height !== img2.height) {
|
|
65
61
|
// resolve(`Screenshot was ${img2.width}x${img2.height} but should be ${img1.width}x${img1.height}:\n${testImg}`);
|
|
66
62
|
|
|
67
|
-
|
|
68
63
|
reject({
|
|
69
64
|
message: 'Screenshot was not the right size',
|
|
70
65
|
expected: `${img1.width}x${img1.height}`,
|
|
71
66
|
actual: `${img2.width}x${img2.height}`,
|
|
72
|
-
files: [testImg, truthImg, path.resolve(SCREENSHOTS)]
|
|
67
|
+
files: [testImg, truthImg, path.resolve(SCREENSHOTS)],
|
|
73
68
|
});
|
|
74
69
|
return;
|
|
75
70
|
}
|
|
76
71
|
|
|
77
72
|
// Do the visual diff.
|
|
78
73
|
const diff = new PNG({ width: img1.width, height: img2.height });
|
|
79
|
-
const matchOptions = {
|
|
80
|
-
|
|
74
|
+
const matchOptions = {
|
|
75
|
+
threshold: threshold || 0.3,
|
|
76
|
+
includeAA: false,
|
|
77
|
+
diffColor: [255, 0, 0],
|
|
78
|
+
aaColor: [0, 0, 255],
|
|
79
|
+
};
|
|
80
|
+
const numDiffPixels =
|
|
81
|
+
excluded != null && excluded.length != 0
|
|
81
82
|
? dynamicpixelmatch(
|
|
82
83
|
img1.data,
|
|
83
84
|
img2.data,
|
|
@@ -101,9 +102,12 @@ const checkScreenshot = async (filename, excluded, threshold) => {
|
|
|
101
102
|
// console.error("number of different pixels are not 0");
|
|
102
103
|
const diffImg = await getPath(DIFF, filename);
|
|
103
104
|
diff.pack().pipe(fs.createWriteStream(diffImg));
|
|
104
|
-
reject({
|
|
105
|
-
|
|
106
|
-
|
|
105
|
+
reject({
|
|
106
|
+
message: 'Pixel match failed',
|
|
107
|
+
files: [diffImg, testImg, truthImg, path.resolve(SCREENSHOTS)],
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
resolve('success');
|
|
107
111
|
};
|
|
108
112
|
|
|
109
113
|
let filesRead = 0;
|
|
@@ -114,18 +118,16 @@ const checkScreenshot = async (filename, excluded, threshold) => {
|
|
|
114
118
|
const img1 = fs
|
|
115
119
|
.createReadStream(truthImg)
|
|
116
120
|
.pipe(new PNG())
|
|
117
|
-
.on(
|
|
118
|
-
|
|
121
|
+
.on('parsed', await doneReading);
|
|
122
|
+
|
|
119
123
|
const img2 = fs
|
|
120
124
|
.createReadStream(testImg)
|
|
121
125
|
.pipe(new PNG())
|
|
122
|
-
.on(
|
|
126
|
+
.on('parsed', await doneReading);
|
|
123
127
|
});
|
|
124
128
|
};
|
|
125
129
|
|
|
126
|
-
|
|
127
130
|
const wireScreenshots = async (page, context) => {
|
|
128
|
-
|
|
129
131
|
// clear out any past tests
|
|
130
132
|
const diffs = path.resolve(SCREENSHOTS, DIFF);
|
|
131
133
|
const tests = path.resolve(SCREENSHOTS, TEST);
|
|
@@ -133,111 +135,108 @@ const wireScreenshots = async (page, context) => {
|
|
|
133
135
|
rimraf.sync(diffs);
|
|
134
136
|
rimraf.sync(tests);
|
|
135
137
|
|
|
136
|
-
await page.exposeFunction(
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
if (wDiff < .15) {
|
|
163
|
-
clip.width = width;
|
|
164
|
-
}
|
|
138
|
+
await page.exposeFunction(
|
|
139
|
+
'matchPageSnapshot',
|
|
140
|
+
(filename, clip, excluded, threshold) => {
|
|
141
|
+
return new Promise(async (resolve, reject) => {
|
|
142
|
+
const testFile = await getPath(TEST, filename);
|
|
143
|
+
const truthFile = await getPath(TRUTH, filename);
|
|
144
|
+
|
|
145
|
+
if (!(await fileExists(truthFile))) {
|
|
146
|
+
// no truth yet, record it
|
|
147
|
+
await page.screenshot({ path: truthFile, clip });
|
|
148
|
+
} else {
|
|
149
|
+
// if its close, force our file to be the same size as our truth for pixelmatch
|
|
150
|
+
const dimensions = sizeOf(truthFile);
|
|
151
|
+
let { width, height } = dimensions;
|
|
152
|
+
|
|
153
|
+
// we should have a device ratio of 2
|
|
154
|
+
width /= 2;
|
|
155
|
+
height /= 2;
|
|
156
|
+
|
|
157
|
+
const wDiff = Math.abs((clip.width - width) / width);
|
|
158
|
+
const hDiff = Math.abs((clip.height - height) / height);
|
|
159
|
+
|
|
160
|
+
if (wDiff < 0.15) {
|
|
161
|
+
clip.width = width;
|
|
162
|
+
}
|
|
165
163
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
164
|
+
if (hDiff < 0.15) {
|
|
165
|
+
clip.height = height;
|
|
166
|
+
}
|
|
169
167
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
168
|
+
if (!clip.width || !clip.height) {
|
|
169
|
+
reject({ message: "Couldn't take screenshot clip is empty" });
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
174
172
|
|
|
175
|
-
|
|
176
|
-
|
|
173
|
+
// create a test screenshot to compare with our truth
|
|
174
|
+
await page.screenshot({ path: testFile, clip });
|
|
177
175
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
176
|
+
try {
|
|
177
|
+
const result = await checkScreenshot(filename);
|
|
178
|
+
resolve(result);
|
|
179
|
+
} catch (error) {
|
|
180
|
+
reject(error);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
184
183
|
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
resolve(true);
|
|
188
|
-
|
|
189
|
-
});
|
|
190
184
|
|
|
191
|
-
|
|
185
|
+
resolve(true);
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
);
|
|
192
189
|
|
|
193
|
-
await page.exposeFunction(
|
|
190
|
+
await page.exposeFunction('setViewport', async options => {
|
|
194
191
|
await page.setViewport(options);
|
|
195
192
|
});
|
|
196
|
-
|
|
197
|
-
await page.exposeFunction(
|
|
193
|
+
|
|
194
|
+
await page.exposeFunction('waitFor', millis => {
|
|
198
195
|
return new Promise(async (resolve, reject) => {
|
|
199
196
|
await page.waitForTimeout(millis);
|
|
200
197
|
resolve();
|
|
201
198
|
});
|
|
202
199
|
});
|
|
203
200
|
|
|
204
|
-
await page.exposeFunction(
|
|
201
|
+
await page.exposeFunction('moveMouse', (x, y) => {
|
|
205
202
|
return new Promise(async (resolve, reject) => {
|
|
206
|
-
await page.mouse.move(x,y);
|
|
203
|
+
await page.mouse.move(x, y);
|
|
207
204
|
resolve();
|
|
208
205
|
});
|
|
209
206
|
});
|
|
210
207
|
|
|
211
|
-
await page.exposeFunction(
|
|
212
|
-
const frame = await page.frames().find(
|
|
208
|
+
await page.exposeFunction('click', async element => {
|
|
209
|
+
const frame = await page.frames().find(f => {
|
|
213
210
|
return true;
|
|
214
211
|
});
|
|
215
212
|
const ele = await frame.$(element);
|
|
216
213
|
await ele.click({});
|
|
217
214
|
});
|
|
218
215
|
|
|
219
|
-
await page.exposeFunction(
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
216
|
+
await page.exposeFunction(
|
|
217
|
+
'typeInto',
|
|
218
|
+
async (selector, text, replace = false) => {
|
|
219
|
+
// console.log("frames", page.frames().length);
|
|
220
|
+
const frame = await page.frames().find(f => {
|
|
221
|
+
return true;
|
|
222
|
+
});
|
|
223
|
+
const element = await frame.$(selector);
|
|
224
|
+
|
|
225
|
+
await element.click({ clickCount: replace ? 3 : 1 });
|
|
226
|
+
await page.keyboard.type(text);
|
|
227
|
+
}
|
|
228
|
+
);
|
|
229
229
|
|
|
230
|
-
await page.exposeFunction(
|
|
231
|
-
for (let i=0; i<times; i++) {
|
|
230
|
+
await page.exposeFunction('pressKey', async (key, times, options) => {
|
|
231
|
+
for (let i = 0; i < times; i++) {
|
|
232
232
|
await page.keyboard.press(key, options);
|
|
233
233
|
}
|
|
234
234
|
});
|
|
235
235
|
|
|
236
|
-
await page.exposeFunction(
|
|
236
|
+
await page.exposeFunction('type', async text => {
|
|
237
237
|
await page.keyboard.type(text);
|
|
238
238
|
});
|
|
239
|
-
}
|
|
240
|
-
|
|
239
|
+
};
|
|
241
240
|
|
|
242
241
|
export default {
|
|
243
242
|
rootDir: './',
|
|
@@ -248,7 +247,12 @@ export default {
|
|
|
248
247
|
name: 'add-style',
|
|
249
248
|
transform(context) {
|
|
250
249
|
if (context.response.is('html')) {
|
|
251
|
-
return {
|
|
250
|
+
return {
|
|
251
|
+
body: context.body.replace(
|
|
252
|
+
/<head>/,
|
|
253
|
+
`<head><link rel="stylesheet" href="/test-assets/style.css">`
|
|
254
|
+
),
|
|
255
|
+
};
|
|
252
256
|
}
|
|
253
257
|
},
|
|
254
258
|
},
|
|
@@ -267,32 +271,38 @@ export default {
|
|
|
267
271
|
browsers: [
|
|
268
272
|
puppeteerLauncher({
|
|
269
273
|
launchOptions: {
|
|
274
|
+
args: [
|
|
275
|
+
'--font-render-hinsting=none',
|
|
276
|
+
'--hide-scrollbars',
|
|
277
|
+
'--disable-web-security',
|
|
278
|
+
],
|
|
270
279
|
headless: true,
|
|
271
280
|
},
|
|
272
|
-
createBrowserContext: (
|
|
281
|
+
createBrowserContext: ({ browser, config }) =>
|
|
282
|
+
browser.defaultBrowserContext(),
|
|
273
283
|
createPage: async ({ context, config }) => {
|
|
274
284
|
const page = await context.newPage();
|
|
275
|
-
await page.exposeFunction(
|
|
285
|
+
await page.exposeFunction('readStaticFile', filename => {
|
|
276
286
|
try {
|
|
277
|
-
var content = fs.readFileSync(
|
|
287
|
+
var content = fs.readFileSync('./' + filename, 'utf8');
|
|
278
288
|
return content;
|
|
279
|
-
} catch(err) {
|
|
289
|
+
} catch (err) {
|
|
280
290
|
console.log(err);
|
|
281
291
|
}
|
|
282
|
-
return
|
|
283
|
-
})
|
|
284
|
-
|
|
292
|
+
return 'Not Found';
|
|
293
|
+
});
|
|
294
|
+
|
|
285
295
|
await page.once('load', async () => {
|
|
286
|
-
await page.addScriptTag(
|
|
296
|
+
await page.addScriptTag({
|
|
297
|
+
content: `
|
|
287
298
|
window.watched = ${config.watch};
|
|
288
|
-
|
|
299
|
+
`,
|
|
300
|
+
});
|
|
289
301
|
await wireScreenshots(page, context);
|
|
290
302
|
});
|
|
291
|
-
|
|
303
|
+
|
|
292
304
|
return page;
|
|
293
305
|
},
|
|
294
|
-
|
|
306
|
+
}),
|
|
295
307
|
],
|
|
296
308
|
};
|
|
297
|
-
|
|
298
|
-
|