@testomatio/reporter 1.2.2-beta-html-pagination-feature → 1.2.2-beta.show-error.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.
- package/lib/pipe/html.js +35 -78
- package/lib/pipe/testomatio.js +25 -0
- package/lib/template/template-draft.hbs +249 -0
- package/lib/template/testomatio.hbs +337 -1175
- package/package.json +1 -1
package/lib/pipe/html.js
CHANGED
|
@@ -91,7 +91,7 @@ class HtmlPipe {
|
|
|
91
91
|
// GENERATE HTML reports based on the results data
|
|
92
92
|
this.buildReport({
|
|
93
93
|
runParams,
|
|
94
|
-
// TODO: this.tests=[] in case of Mocha
|
|
94
|
+
// TODO: this.tests=[] in case of Mocha
|
|
95
95
|
tests: this.tests,
|
|
96
96
|
outputPath: this.htmlOutputPath,
|
|
97
97
|
templatePath: this.templateHtmlPath,
|
|
@@ -198,10 +198,8 @@ class HtmlPipe {
|
|
|
198
198
|
const template = handlebars.compile(templateSource);
|
|
199
199
|
|
|
200
200
|
return template(data);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
console.log(chalk.red("❌ Oops! An unknown error occurred when generating an HTML report"));
|
|
204
|
-
console.log(chalk.red(e));
|
|
201
|
+
} catch (e) {
|
|
202
|
+
console.log('Unknown HTML report generation error: ', e);
|
|
205
203
|
}
|
|
206
204
|
}
|
|
207
205
|
|
|
@@ -211,84 +209,43 @@ class HtmlPipe {
|
|
|
211
209
|
(tests, status) => tests.filter(test => test.status.toLowerCase() === status.toLowerCase()).length,
|
|
212
210
|
);
|
|
213
211
|
|
|
214
|
-
handlebars.registerHelper(
|
|
215
|
-
|
|
216
|
-
()
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
);
|
|
233
|
-
|
|
234
|
-
handlebars.registerHelper(
|
|
235
|
-
'pageDispleyElements',
|
|
236
|
-
tests => {
|
|
237
|
-
// We wrapp the lines to the HTML format we need
|
|
238
|
-
const totalTests =
|
|
239
|
-
JSON.parse(
|
|
240
|
-
JSON.stringify(tests)
|
|
241
|
-
.replace(/<script>/g, '<script>')
|
|
242
|
-
.replace(/<\/script>/g, '<\/script>') // eslint-disable-line
|
|
243
|
-
);
|
|
244
|
-
|
|
245
|
-
const paginationOptions = {
|
|
246
|
-
'0': 10,
|
|
247
|
-
'1': 25,
|
|
248
|
-
'2': 50
|
|
249
|
-
};
|
|
250
|
-
const statuses = [
|
|
251
|
-
'all',
|
|
252
|
-
'passed',
|
|
253
|
-
'failed',
|
|
254
|
-
'skipped'
|
|
255
|
-
];
|
|
256
|
-
const pageItemGroups = {
|
|
257
|
-
'all': {},
|
|
258
|
-
'passed': {},
|
|
259
|
-
'failed': {},
|
|
260
|
-
'skipped': {},
|
|
261
|
-
'totalTests': totalTests
|
|
262
|
-
};
|
|
263
|
-
|
|
264
|
-
function paginateItems(items, pageSize) {
|
|
265
|
-
const paginatedItems = [];
|
|
266
|
-
for (let i = 0; i < items.length; i += pageSize) {
|
|
267
|
-
paginatedItems.push(items.slice(i, i + pageSize));
|
|
268
|
-
}
|
|
269
|
-
return paginatedItems;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
statuses.forEach(status => {
|
|
273
|
-
for (const option in paginationOptions) {
|
|
274
|
-
if (Object.hasOwnProperty.call(paginationOptions, option)) {
|
|
275
|
-
const pageSize = paginationOptions[option];
|
|
276
|
-
let filteredItems = totalTests;
|
|
277
|
-
|
|
278
|
-
if (status !== 'all') {
|
|
279
|
-
filteredItems = totalTests.filter(item => item.status === status);
|
|
212
|
+
handlebars.registerHelper('json', tests => {
|
|
213
|
+
// TODO: please refactor the code below, add meaningful variable names, separate into functions
|
|
214
|
+
function replaceScriptTagsInArray(array) {
|
|
215
|
+
return array.map(obj => {
|
|
216
|
+
const keysToCheck = ['steps', 'stack', 'title', 'suite_title', 'message', 'code'];
|
|
217
|
+
const newObj = {};
|
|
218
|
+
|
|
219
|
+
for (const key in obj) {
|
|
220
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
221
|
+
if (key === 'example') {
|
|
222
|
+
newObj[key] = {};
|
|
223
|
+
for (const subKey in obj[key]) {
|
|
224
|
+
if (Object.prototype.hasOwnProperty.call(obj[key], subKey)) {
|
|
225
|
+
newObj[key][subKey] =
|
|
226
|
+
typeof obj[key][subKey] === 'string'
|
|
227
|
+
? obj[key][subKey].replace(/<script>/g, '<$cript>').replace(/<\/script>/g, '</$cript>')
|
|
228
|
+
: obj[key][subKey];
|
|
229
|
+
}
|
|
280
230
|
}
|
|
281
|
-
|
|
282
|
-
|
|
231
|
+
} else if (keysToCheck.includes(key)) {
|
|
232
|
+
newObj[key] =
|
|
233
|
+
typeof obj[key] === 'string'
|
|
234
|
+
? obj[key].replace(/<script>/g, '<$cript>').replace(/<\/script>/g, '</$cript>')
|
|
235
|
+
: obj[key];
|
|
236
|
+
} else {
|
|
237
|
+
newObj[key] = obj[key];
|
|
283
238
|
}
|
|
239
|
+
}
|
|
284
240
|
}
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
pageItemGroups.totalTests = totalTests;
|
|
288
241
|
|
|
289
|
-
|
|
242
|
+
return newObj;
|
|
243
|
+
});
|
|
290
244
|
}
|
|
291
|
-
|
|
245
|
+
|
|
246
|
+
// Remove ANSI escape codes
|
|
247
|
+
return JSON.stringify(replaceScriptTagsInArray(tests));
|
|
248
|
+
});
|
|
292
249
|
}
|
|
293
250
|
|
|
294
251
|
toString() {
|
package/lib/pipe/testomatio.js
CHANGED
|
@@ -190,6 +190,7 @@ class TestomatioPipe {
|
|
|
190
190
|
'Error creating Testomat.io report, please check if your API key is valid. Skipping report | ',
|
|
191
191
|
err?.response?.statusText || err?.status || err.message,
|
|
192
192
|
);
|
|
193
|
+
printCreateIssue(err);
|
|
193
194
|
}
|
|
194
195
|
debug('"createRun" function finished');
|
|
195
196
|
}
|
|
@@ -231,8 +232,11 @@ class TestomatioPipe {
|
|
|
231
232
|
chalk.yellow(`Warning: ${data?.title || ''} (${err.response?.status})`),
|
|
232
233
|
`Report couldn't be processed: ${err?.response?.data?.message}`,
|
|
233
234
|
);
|
|
235
|
+
printCreateIssue(err);
|
|
234
236
|
} else {
|
|
235
237
|
console.log(APP_PREFIX, chalk.blue(data?.title || ''), "Report couldn't be processed", err);
|
|
238
|
+
|
|
239
|
+
|
|
236
240
|
}
|
|
237
241
|
});
|
|
238
242
|
}
|
|
@@ -300,6 +304,7 @@ class TestomatioPipe {
|
|
|
300
304
|
}
|
|
301
305
|
} catch (err) {
|
|
302
306
|
console.log(APP_PREFIX, 'Error updating status, skipping...', err);
|
|
307
|
+
printCreateIssue(err);
|
|
303
308
|
}
|
|
304
309
|
debug('Run finished');
|
|
305
310
|
}
|
|
@@ -309,4 +314,24 @@ class TestomatioPipe {
|
|
|
309
314
|
}
|
|
310
315
|
}
|
|
311
316
|
|
|
317
|
+
let registeredErrorHints = false;
|
|
318
|
+
function printCreateIssue(err) {
|
|
319
|
+
if (registeredErrorHints) return;
|
|
320
|
+
registeredErrorHints = true;
|
|
321
|
+
process.on('beforeExit', () => {
|
|
322
|
+
console.log(APP_PREFIX, 'There was error reporting to Testomat.io:');
|
|
323
|
+
console.log(APP_PREFIX, 'If you think this is a bug please create an issue: https://github.com/testomatio/app/issues/new');
|
|
324
|
+
console.log(APP_PREFIX, 'Provide this information:');
|
|
325
|
+
console.log(APP_PREFIX, 'Error:', err.message || err.code);
|
|
326
|
+
if (!err.config) return;
|
|
327
|
+
|
|
328
|
+
const time = new Date().toUTCString();
|
|
329
|
+
const { data, url, baseURL, method } = err?.config || {}
|
|
330
|
+
console.log('```js')
|
|
331
|
+
console.log({ data, url, baseURL, method, time });
|
|
332
|
+
console.log('```')
|
|
333
|
+
console.log();
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
|
|
312
337
|
module.exports = TestomatioPipe;
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<link href="https://fonts.googleapis.com/css2?family=Fira+Mono:wght@400;500;700&display=swap" rel="stylesheet">
|
|
7
|
+
<link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">
|
|
8
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/accordionjs@2.1.2/accordion.min.css">
|
|
9
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
|
10
|
+
<title>Report {{runId}} - Testomat.io</title>
|
|
11
|
+
<link rel="stylesheet" href="./style.css">
|
|
12
|
+
{{!-- TODO: styling create as a new additional file instead of template => copy default one --}}
|
|
13
|
+
<style>
|
|
14
|
+
body {
|
|
15
|
+
font-family: "Fira Sans", sans-serif;
|
|
16
|
+
}
|
|
17
|
+
</style>
|
|
18
|
+
</head>
|
|
19
|
+
|
|
20
|
+
<body class="bg-gray-50 pt-6 px-4 lg:pt-4 lg:px-40 h-full;">
|
|
21
|
+
<div id="testomatio_report">
|
|
22
|
+
<div class="flex items-center flex-col space-y-4 md:flex-row md:justify-between md:h-14 mb-6">
|
|
23
|
+
<div class="flex flex-col md:flex-row space-x-3 items-center">
|
|
24
|
+
<h2 class="text-gray-900 leading-none text-3xl font-semibold mb-0">{{runId}}
|
|
25
|
+
</h2>
|
|
26
|
+
{{!-- <span class="text-sm text-gray-500">
|
|
27
|
+
{{executionDate}}
|
|
28
|
+
</span> --}}
|
|
29
|
+
</div>
|
|
30
|
+
<div class="flex space-x-3 items-center">
|
|
31
|
+
<a class="inline-flex items-center border border-transparent leading-none text-white bg-indigo-500 hover:bg-indigo-700 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 cursor-pointer px-4 py-2 text-base leading-none"
|
|
32
|
+
style="min-height: 38px"
|
|
33
|
+
href="{{runUrl}}"
|
|
34
|
+
target="_blank">
|
|
35
|
+
Full Report
|
|
36
|
+
</a>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
<div class="bg-white border overflow-hidden rounded-lg divide-y divide-gray-200 mb-12">
|
|
40
|
+
<div class="flex flex-col lg:divide-x divide-gray-200 sm:flex-col md:flex-col lg:flex-row">
|
|
41
|
+
<div class="w-full lg:w-1/2">
|
|
42
|
+
<!-- Left chart section -->
|
|
43
|
+
<div class="p-4">
|
|
44
|
+
<h2 class="text-xl font-semibold mb-4">Testomatio Test Results</h2>
|
|
45
|
+
<span class="text-sm text-gray-500 items-center">{{executionDate}}</span>
|
|
46
|
+
<div class="hart-container" style="height: 200px;">
|
|
47
|
+
<canvas id="testomatio_chart"></canvas>
|
|
48
|
+
<div for="testomatio_chart"></div>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
<div class="w-full lg:w-1/2">
|
|
53
|
+
<!-- Right chart section -->
|
|
54
|
+
<div class="p-4">
|
|
55
|
+
<h2 class="text-xl font-semibold mb-4">Testomatio Run Info</h2>
|
|
56
|
+
<dl>
|
|
57
|
+
<div class="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
|
58
|
+
<dt class="text-sm font-medium text-gray-500">
|
|
59
|
+
RUN Status
|
|
60
|
+
</dt>
|
|
61
|
+
<dd class="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
|
|
62
|
+
<span class="inline-flex items-center justify-center px-2 py-0.5 text-xs font-bold leading-none bg-green-200 text-green-600 rounded-full">
|
|
63
|
+
{{status}}
|
|
64
|
+
</span>
|
|
65
|
+
</dd>
|
|
66
|
+
</div>
|
|
67
|
+
<div class="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
|
68
|
+
<dt class="text-sm font-medium text-gray-500">
|
|
69
|
+
Duration
|
|
70
|
+
</dt>
|
|
71
|
+
<dd class="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
|
|
72
|
+
<span>
|
|
73
|
+
<i class="fa fa-clock-o"></i>
|
|
74
|
+
</span>
|
|
75
|
+
{{executionTime}}
|
|
76
|
+
</dd>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
</dl>
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
|
|
85
|
+
<div class="px-4 py-5 lg:px-20 lg:py-5">
|
|
86
|
+
<!-- TODO: maybe add a search section by test NAME!! -->
|
|
87
|
+
<div class="px-4 py-5 lg:px-20 lg:py-5 border rounded-md mb-4">
|
|
88
|
+
<div class="mb-2">
|
|
89
|
+
<h3 class="text-2xl leading-10 font-medium text-gray-900">
|
|
90
|
+
Search and Summary
|
|
91
|
+
</h3>
|
|
92
|
+
</div>
|
|
93
|
+
<div class="flex items-center space-x-4">
|
|
94
|
+
<div class="relative">
|
|
95
|
+
<input type="text" id="search-input" placeholder="Search by test title..." class="border rounded-md py-1 px-2 w-48 focus:outline-none focus:ring focus:border-blue-300">
|
|
96
|
+
|
|
97
|
+
</div>
|
|
98
|
+
<div class="test-status">
|
|
99
|
+
<div class="flex items-center">
|
|
100
|
+
<span class="font-medium mr-2">All:</span>
|
|
101
|
+
<span class="text-blue-600 font-semibold">{{tests.length}}</span>
|
|
102
|
+
<span class="font-medium ml-4 mr-2">Passed:</span>
|
|
103
|
+
<span class="text-green-600 font-semibold">{{getTestsByStatus tests "PASSED"}}</span>
|
|
104
|
+
<span class="font-medium ml-4 mr-2">Failed:</span>
|
|
105
|
+
<span class="text-red-600 font-semibold">{{getTestsByStatus tests "FAILED"}}</span>
|
|
106
|
+
<span class="font-medium ml-4 mr-2">Skipped:</span>
|
|
107
|
+
<span class="text-yellow-600 font-semibold">{{getTestsByStatus tests "SKIPPED"}}</span>
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
|
|
114
|
+
<ul class="accordionjs bg-gray-50 rounded-md divide-y divide-gray-200 text-gray-900">
|
|
115
|
+
<li class="pl-3 pr-4 py-3 text-sm cursor-pointer">
|
|
116
|
+
<h4 class="text-lg flex items-center space-x-1">
|
|
117
|
+
<span class="font-medium">Passed</span>
|
|
118
|
+
<span class="inline-flex items-center justify-center px-2 py-0.5 text-xs font-bold leading-none bg-green-200 text-green-600 rounded-full">
|
|
119
|
+
{{getTestsByStatus tests "PASSED"}}
|
|
120
|
+
</span>
|
|
121
|
+
</h4>
|
|
122
|
+
<ul role="list" class="pl-2 divide-y divide-gray-200">
|
|
123
|
+
{{#each tests}}
|
|
124
|
+
<ul role="list" class="pl-2 divide-y divide-gray-200">
|
|
125
|
+
{{#eq status "passed"}}
|
|
126
|
+
<li class="py-3 flex justify-between items-center">
|
|
127
|
+
<div>
|
|
128
|
+
<div class="success"></div>
|
|
129
|
+
<a class="testrun hover:underline" data-toggle="test-{{test_id}}" data-target="test-code-{{test_id}}">
|
|
130
|
+
{{title}} title
|
|
131
|
+
</a>
|
|
132
|
+
</div>
|
|
133
|
+
<dd class="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
|
|
134
|
+
<span>
|
|
135
|
+
<i class="fa fa-clock-o"></i>
|
|
136
|
+
</span>
|
|
137
|
+
{{#if run_time}}
|
|
138
|
+
{{run_time}}ms
|
|
139
|
+
{{/if}}
|
|
140
|
+
</dd>
|
|
141
|
+
</li>
|
|
142
|
+
<li class="py-3 test-code-container test-code" id="test-code-{{test_id}}">
|
|
143
|
+
<pre>
|
|
144
|
+
<code>
|
|
145
|
+
{{steps}}
|
|
146
|
+
</code>
|
|
147
|
+
</pre>
|
|
148
|
+
</li>
|
|
149
|
+
{{/eq}}
|
|
150
|
+
</ul>
|
|
151
|
+
{{/each}}
|
|
152
|
+
</ul>
|
|
153
|
+
</li>
|
|
154
|
+
|
|
155
|
+
<li class="pl-3 pr-4 py-3 text-sm cursor-pointer">
|
|
156
|
+
<h4 class="text-lg flex items-center space-x-1">
|
|
157
|
+
<span class="font-medium">Failed</span>
|
|
158
|
+
<span class="inline-flex items-center justify-center px-2 py-0.5 text-xs font-bold leading-none bg-red-200 text-red-500 rounded-full">
|
|
159
|
+
{{getTestsByStatus tests "FAILED"}}
|
|
160
|
+
</span>
|
|
161
|
+
</h4>
|
|
162
|
+
|
|
163
|
+
<ul role="list" class="pl-2 divide-y divide-gray-200">
|
|
164
|
+
{{#each tests}}
|
|
165
|
+
{{#eq status "failed"}}
|
|
166
|
+
<li class="py-3 flex justify-between items-center">
|
|
167
|
+
<div>
|
|
168
|
+
<div class="fail"></div>
|
|
169
|
+
<a class="testrun hover:underline" data-toggle="test-{{test_id}}" data-target="test-code-{{test_id}}">
|
|
170
|
+
{{title}} title
|
|
171
|
+
</a>
|
|
172
|
+
</div>
|
|
173
|
+
<dd class="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
|
|
174
|
+
<span>
|
|
175
|
+
<i class="fa fa-clock-o"></i>
|
|
176
|
+
</span>
|
|
177
|
+
{{#if run_time}}
|
|
178
|
+
{{run_time}}ms
|
|
179
|
+
{{/if}}
|
|
180
|
+
</dd>
|
|
181
|
+
</li>
|
|
182
|
+
<li class="py-3 test-code-container test-code" id="test-code-{{test_id}}">
|
|
183
|
+
<pre>
|
|
184
|
+
<code>
|
|
185
|
+
{{steps}}
|
|
186
|
+
</code>
|
|
187
|
+
</pre>
|
|
188
|
+
</li>
|
|
189
|
+
{{/eq}}
|
|
190
|
+
{{/each}}
|
|
191
|
+
</ul>
|
|
192
|
+
</li>
|
|
193
|
+
</ul>
|
|
194
|
+
</div>
|
|
195
|
+
</div>
|
|
196
|
+
<div
|
|
197
|
+
class="fixed bg-white border-t inset-x-0 bottom-0 mx-auto py-1 px-3 sm:px-6 lg:px-8 flex items-center justify-between flex-wrap">
|
|
198
|
+
<p class="ml-3 text-gray-500 text-xs lg:truncate">
|
|
199
|
+
This is a public report generated by <a class="hover:underline text-gray-700 font-semibold"
|
|
200
|
+
href="https://testomat.io" target="_blank">Testomat.io</a>. Everyone who has accesse to this link can
|
|
201
|
+
see this report.<br>
|
|
202
|
+
</p>
|
|
203
|
+
</div>
|
|
204
|
+
|
|
205
|
+
</body>
|
|
206
|
+
<!-- Jquery from a CDN -->
|
|
207
|
+
<script type="module" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.3.2/chart.min.js"></script>
|
|
208
|
+
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
|
|
209
|
+
<script src="https://cdn.jsdelivr.net/npm/accordionjs@2.1.2/accordion.min.js"></script>
|
|
210
|
+
<!-- Chart.js from a CDN -->
|
|
211
|
+
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
212
|
+
|
|
213
|
+
<!-- Include Handlebars from a CDN -->
|
|
214
|
+
<script src="https://cdn.jsdelivr.net/npm/handlebars@latest/dist/handlebars.js"></script>
|
|
215
|
+
<!-- Handlebars tamplate actions -->
|
|
216
|
+
<script>
|
|
217
|
+
$(document).ready(function ($) {
|
|
218
|
+
$(".accordionjs").accordionjs();
|
|
219
|
+
|
|
220
|
+
$('#copy-url').on('click', () => {
|
|
221
|
+
navigator.clipboard.writeText(window.location.href);
|
|
222
|
+
})
|
|
223
|
+
});
|
|
224
|
+
//Open code section handler
|
|
225
|
+
document.querySelectorAll('.test-code').forEach(element => {
|
|
226
|
+
element.style.display = 'none';
|
|
227
|
+
});
|
|
228
|
+
const testrunLinks = document.querySelectorAll('.testrun');
|
|
229
|
+
|
|
230
|
+
testrunLinks.forEach(link => {
|
|
231
|
+
link.addEventListener('click', function () {
|
|
232
|
+
// get "data-toggle" & "data-target" from link env
|
|
233
|
+
const toggleId = this.getAttribute('data-toggle');
|
|
234
|
+
const targetId = this.getAttribute('data-target');
|
|
235
|
+
|
|
236
|
+
// get "tests.code" elements and change view
|
|
237
|
+
const targetElement = document.querySelector(`#${targetId}`);
|
|
238
|
+
|
|
239
|
+
// SET "tests.code" viewing after each click
|
|
240
|
+
if (targetElement.style.display === 'none') {
|
|
241
|
+
targetElement.style.display = 'block';
|
|
242
|
+
} else {
|
|
243
|
+
targetElement.style.display = 'none';
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
</script>
|
|
248
|
+
<script type="text/javascript" src="./chart-my.js"></script>
|
|
249
|
+
</html>
|