testaro 8.0.1 → 8.0.2
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/README.md +82 -66
- package/{do.js → call.js} +10 -10
- package/package.json +7 -3
package/README.md
CHANGED
|
@@ -6,11 +6,11 @@ Federated accessibility test automation
|
|
|
6
6
|
|
|
7
7
|
Testaro is a collection of collections of web accessibility tests.
|
|
8
8
|
|
|
9
|
-
The purpose of Testaro is to provide programmatic access to accessibility tests defined in several test packages
|
|
9
|
+
The purpose of Testaro is to provide programmatic access to accessibility tests defined in several test packages, including Testaro itself.
|
|
10
10
|
|
|
11
11
|
Testaro launches and controls web browsers, performing operations, conducting tests, and recording results.
|
|
12
12
|
|
|
13
|
-
Testaro is designed to be a workstation-based agent. Testaro can be installed on a workstation running under OS X or Windows, or potentially Ubuntu Linux.
|
|
13
|
+
Testaro is designed to be a workstation-based agent. Testaro can be installed on a workstation running under OS X or Windows, or potentially Ubuntu Linux. Software that uses Testaro can be installed on the same workstation or any other workstation or server. Such other software can perform functions that do not require workstation features, such as:
|
|
14
14
|
- Test scheduling
|
|
15
15
|
- Monitoring
|
|
16
16
|
- Management of clusters of workstations sharing workloads
|
|
@@ -19,7 +19,7 @@ Testaro is designed to be a workstation-based agent. Testaro can be installed on
|
|
|
19
19
|
- Converting user specifications into instructions for workstations
|
|
20
20
|
- Allocating testing responsibilities to human testers
|
|
21
21
|
- Combining reports from workstations and human testers
|
|
22
|
-
- Analyzing and summarizing test results
|
|
22
|
+
- Analyzing and summarizing (e.g., computing scores on the basis of) test results
|
|
23
23
|
- Sending notifications
|
|
24
24
|
- Publishing reports
|
|
25
25
|
|
|
@@ -107,7 +107,7 @@ All of the tests that Testaro can perform are free of cost, except those in the
|
|
|
107
107
|
|
|
108
108
|
## Jobs
|
|
109
109
|
|
|
110
|
-
A request to
|
|
110
|
+
A request to Testaro to do some work is a _job_.
|
|
111
111
|
|
|
112
112
|
## Scripts
|
|
113
113
|
|
|
@@ -163,11 +163,11 @@ Here is an example of a script:
|
|
|
163
163
|
}
|
|
164
164
|
```
|
|
165
165
|
|
|
166
|
-
This script tells Testaro to open a page in the Chromium browser, navigate to `example.com`, and perform the tests in the `alfa` package on that URL, within 65 seconds.
|
|
166
|
+
This script tells Testaro to open a page in the Chromium browser, navigate to `example.com`, and, if the browser is not redirected, perform the tests in the `alfa` package on that URL, within 65 seconds.
|
|
167
167
|
|
|
168
168
|
### Strictness
|
|
169
169
|
|
|
170
|
-
If the `strict` property is `true`, Testaro will accept redirections that add or subtract a final slash, but otherwise will treat redirections as failures.
|
|
170
|
+
If the `strict` property is `true`, Testaro will accept redirections that add or subtract a final slash, but otherwise will treat redirections as failures. For example, a redirection from `xyz.com` to `www.xyz.com` or `xyz.com/en` will abort the job.
|
|
171
171
|
|
|
172
172
|
### Commands
|
|
173
173
|
|
|
@@ -207,7 +207,7 @@ In this case, Testaro checks the third radio button whose text includes the stri
|
|
|
207
207
|
|
|
208
208
|
In identifying the target element for a move, Testaro matches the `which` property with the texts of the elements of the applicable type (such as radio buttons). It defines the text of an `input` element as the concatenated texts of its implicit label or explicit labels, if any, plus, for the first input in a `fieldset` element, the text content of the `legend` element of that `fieldset` element. For any other element, Testaro defines the text as the text content of the element.
|
|
209
209
|
|
|
210
|
-
When multiple elements of the same type
|
|
210
|
+
When the texts of multiple elements of the same type will contain the `which` value, you can include an `index` property to specify the index of the target element, among all those that will match.
|
|
211
211
|
|
|
212
212
|
##### Navigations
|
|
213
213
|
|
|
@@ -215,7 +215,7 @@ An example of a **navigation** is the command of type `url` above.
|
|
|
215
215
|
|
|
216
216
|
Once you have included a `url` command in a script, you do not need to add more `url` commands unless you want the browser to visit a different URL.
|
|
217
217
|
|
|
218
|
-
However, some tests modify web pages. In those cases, Testaro inserts additional `url`
|
|
218
|
+
However, some tests modify web pages. In those cases, Testaro inserts additional `launch` and `url` act pairs into the `acts` array, after those tests, to ensure that changes made by one test do not affect subsequent acts, if the environment variable `URL_INJECT` has the value `yes`.
|
|
219
219
|
|
|
220
220
|
Another navigation example is:
|
|
221
221
|
|
|
@@ -258,7 +258,7 @@ Thus, if a command of type `test` runs Continuum, Continuum performs multiple te
|
|
|
258
258
|
|
|
259
259
|
Every test in Testaro must have:
|
|
260
260
|
- a property in the `tests` object defined in the `run.js` file, where the property name is the name of the test and the value is a description of the test
|
|
261
|
-
- a `.js` file in the `tests` directory, whose name base is the name of the test
|
|
261
|
+
- a `.js` file, defining the test, in the `tests` directory, whose name base is the name of the test
|
|
262
262
|
|
|
263
263
|
The `commands.js` file (described in detail below) contains this specification for any `test` command:
|
|
264
264
|
|
|
@@ -272,7 +272,7 @@ test: [
|
|
|
272
272
|
],
|
|
273
273
|
```
|
|
274
274
|
|
|
275
|
-
That means that a test (i.e. a command with a `type` property having the value `'test'`) must have a string-valued `which` property and may optionally have a string-valued `what` property.
|
|
275
|
+
That means that a test (i.e. a command with a `type` property having the value `'test'`) must have a string-valued `which` property naming a test and may optionally have a string-valued `what` property describing the test.
|
|
276
276
|
|
|
277
277
|
If a particular test either must have or may have any other properties, those properties must be specified in the `tests` property in `commands.js`.
|
|
278
278
|
|
|
@@ -334,7 +334,7 @@ Example:
|
|
|
334
334
|
}
|
|
335
335
|
```
|
|
336
336
|
|
|
337
|
-
The reason for this is that the Tenon API operates asynchronously. You ask it to perform a test, and it puts your request into a queue. To learn whether Tenon has completed your test, you make a status request. You can continue making status requests until Tenon replies that your test has been completed. Then you submit a request for the test result, and Tenon replies with the result. (As of May 2022, status requests were observed to misreport still-running tests as completed. The `tenon` test works around that by requesting only the result and using the response to determine whether the tests have been completed.)
|
|
337
|
+
The reason for this is that the Tenon API operates asynchronously. You ask it to perform a test, and it puts your request into a queue. To learn whether Tenon has completed your test, you make a status request. You can continue making status requests until Tenon replies that your test has been completed. Then you submit a request for the test result, and Tenon replies with the result. (As of May 2022, however, status requests were observed to misreport still-running tests as completed. The `tenon` test works around that by requesting only the result and using the response to determine whether the tests have been completed.)
|
|
338
338
|
|
|
339
339
|
Tenon says that tests are typically completed in 3 to 6 seconds but that the latency can be longer, depending on demand.
|
|
340
340
|
|
|
@@ -390,6 +390,8 @@ The changes in `htmlcs/HTMLCS.js` are:
|
|
|
390
390
|
|
|
391
391
|
If a `wave` test is included in the script, an environment variable named `WAVE_KEY` must exist, with your WAVE API key as its value. You can get it from [WebAIM](https://wave.webaim.org/api/).
|
|
392
392
|
|
|
393
|
+
The `wave` API does not accept a transmitted document for testing. WAVE must be given only a URL, which it then visits to perform its tests. Therefore, you cannot manipulate a page and then have WAVE test it, or ask WAVE to test a page that cannot be reached directly with a URL.
|
|
394
|
+
|
|
393
395
|
###### BBC Accessibility Standards Checker
|
|
394
396
|
|
|
395
397
|
The BBC Accessibility Standards Checker has obsolete dependencies with security vulnerabilities. Therefore, it is not used as a dependency of Testaro. Instead, 6 of its tests are reimplemented, in some cases with revisions, as Testaro tests. They are drawn from the 18 automated tests of the Checker. The other 12 tests were found too duplicative of other tests to justify reimplementation.
|
|
@@ -495,17 +497,36 @@ A typical use for an `expect` property is checking the correctness of a Testaro
|
|
|
495
497
|
|
|
496
498
|
## Samples
|
|
497
499
|
|
|
498
|
-
The `
|
|
500
|
+
The `samples` directory contains examples of scripts. If you wish to use any of them, you can give `SCRIPTDIR` the value `'samples'`.
|
|
499
501
|
|
|
500
502
|
## Execution
|
|
501
503
|
|
|
502
|
-
###
|
|
504
|
+
### Introduction
|
|
505
|
+
|
|
506
|
+
Testaro can be called by modules and by users.
|
|
507
|
+
|
|
508
|
+
### Functions
|
|
503
509
|
|
|
504
|
-
|
|
510
|
+
Testaro contains these modules that export executable functions:
|
|
511
|
+
- `run.js` exports `doJob` for low-level execution.
|
|
512
|
+
- `high.js` exports `runJob` for high-level execution.
|
|
513
|
+
- `watch.js` exports `cycle` for watch-triggered execution.
|
|
514
|
+
|
|
515
|
+
#### Imports
|
|
516
|
+
|
|
517
|
+
Before a module can execute a Testaro function, it must import that function from the module that exports it. A Testaro module can import function `f` from module `m` with the statement
|
|
518
|
+
|
|
519
|
+
```javascript
|
|
520
|
+
const {f} = require('./m');`
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
The argument of `require` is a path relative to the directory of the module in which this code appears. If the module is in a subdirectory, `./m` will need to be revised. In an executor within `validation/executors`, it must be revised to `../../m`.
|
|
524
|
+
|
|
525
|
+
A module in another Node.js package that has Testaro as a dependency can execute the same statements, except changing `'./m'` to `'testaro/m'`.
|
|
505
526
|
|
|
506
527
|
#### Low-level
|
|
507
528
|
|
|
508
|
-
|
|
529
|
+
Low-level execution is designed for a module to create a job and make Testaro run it, as follows:
|
|
509
530
|
|
|
510
531
|
```javascript
|
|
511
532
|
const report = {
|
|
@@ -520,87 +541,81 @@ doJob(report)
|
|
|
520
541
|
|
|
521
542
|
Replace `{…}` with a script object, like the example script shown above.
|
|
522
543
|
|
|
523
|
-
The argument of `require` is a path relative to the directory of the module in which this code appears. If the module is in a subdirectory, `./run` will need to be revised. In an executor within `validation/executors`, it must be revised to `../../run`.
|
|
524
|
-
|
|
525
|
-
Another Node.js package that has Testaro as a dependency can execute the same statements, except changing `'./run'` to `'testaro/run'`.
|
|
526
|
-
|
|
527
544
|
Testaro will run the script and modify the properties of the `report` object. When Testaro finishes, the `log`, `acts`, and other properties of `report` will contain the results. The final statement can further process the `report` object as desired in the `then` callback.
|
|
528
545
|
|
|
529
546
|
#### High-level
|
|
530
547
|
|
|
531
|
-
High-level
|
|
548
|
+
High-level execution is designed for either modules or users.
|
|
532
549
|
|
|
533
|
-
|
|
534
|
-
- `SCRIPTDIR`
|
|
535
|
-
- `REPORTDIR`
|
|
550
|
+
Execution by a module:
|
|
536
551
|
|
|
537
|
-
|
|
552
|
+
```javaScript
|
|
553
|
+
const {runJob} = require('./high');
|
|
554
|
+
runJob('tp123');
|
|
555
|
+
```
|
|
538
556
|
|
|
539
|
-
|
|
557
|
+
Execution by a user:
|
|
540
558
|
|
|
541
|
-
|
|
559
|
+
```bash
|
|
560
|
+
node call high tp123
|
|
561
|
+
```
|
|
542
562
|
|
|
543
|
-
|
|
563
|
+
In either case, replace `tp123` with the base of the name of a script.
|
|
544
564
|
|
|
545
|
-
|
|
565
|
+
Testaro will find the named script (e.g., `tp123.json`) in the `SCRIPTDIR` directory and write the report in the `REPORTDIR` directory.
|
|
546
566
|
|
|
547
567
|
#### Watch
|
|
548
568
|
|
|
549
|
-
|
|
569
|
+
Watch execution is designed for either modules or users.
|
|
550
570
|
|
|
551
|
-
Testaro checks
|
|
571
|
+
In watch mode, Testaro periodically checks for a script to be run by it. When such a script exists, Testaro runs it and provides a report. Testaro may continue watching after the first report, or may quit.
|
|
552
572
|
|
|
553
|
-
|
|
573
|
+
Execution by a module:
|
|
554
574
|
|
|
555
|
-
|
|
575
|
+
```javaScript
|
|
576
|
+
const {cycle} = require('./watch');
|
|
577
|
+
cycle(true, true, 30);
|
|
578
|
+
```
|
|
556
579
|
|
|
557
|
-
|
|
580
|
+
Execution by a user:
|
|
558
581
|
|
|
559
|
-
|
|
582
|
+
```javaScript
|
|
583
|
+
node call watch true true 30
|
|
584
|
+
```
|
|
560
585
|
|
|
561
|
-
|
|
586
|
+
The arguments passed to `cycle` by either of these invocations are:
|
|
587
|
+
- whether to watch a directory (true) or the network (false)
|
|
588
|
+
- whether to continue watching indefinitely after the first report (true or false)
|
|
589
|
+
- how many seconds to wait before checking again (a nonnegative number)
|
|
562
590
|
|
|
563
|
-
|
|
591
|
+
##### Directory watch
|
|
564
592
|
|
|
565
|
-
|
|
593
|
+
With directory watch, Testaro checks whether the watch directory (`WATCHDIR`) in its host’s filesystem contains a script.
|
|
566
594
|
|
|
567
|
-
|
|
595
|
+
When Testaro finds one or more scripts in the watch directory, Testaro runs the first script, writes the report into the `REPORTDIR` directory, and moves the script into the `DONEDIR` directory.
|
|
568
596
|
|
|
569
|
-
|
|
570
|
-
- `WATCH_TYPE=dir`
|
|
571
|
-
- `INTERVAL`
|
|
572
|
-
- `WATCH_FOREVER` (`=true` or `=false`)
|
|
573
|
-
- `REPORTDIR`
|
|
574
|
-
- `WATCHDIR`
|
|
575
|
-
- `DONEDIR`
|
|
597
|
+
Since Testaro runs the first script (i.e. the script whose name is first in ASCII order), whoever populates the `WATCHDIR` directory with script files has control over the order in which Testaro runs them. For example, to force a new script to be run before the already waiting scripts, one can give it a filename that comes before that of the first waiting script.
|
|
576
598
|
|
|
577
599
|
##### Network watch
|
|
578
600
|
|
|
579
|
-
Network watching is
|
|
601
|
+
Network watching is designed for a situation in which:
|
|
580
602
|
- A managing server may be able to give work to multiple workstations that run Testaro.
|
|
581
603
|
- A workstation running Testaro can contact a managing server, but the server may not be able to contact a workstation.
|
|
582
604
|
- The functions of Testaro are limited to those requiring workstation features.
|
|
583
605
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
In order to make network watching possible, you must define these environment variables:
|
|
587
|
-
- `WATCH_TYPE=net`
|
|
588
|
-
- `INTERVAL`
|
|
589
|
-
- `WATCH_FOREVER` (`=true` or `=false`)
|
|
590
|
-
- `PROTOCOL` (`=http` or `=https`)
|
|
591
|
-
- `WATCH_URL`
|
|
592
|
-
- `REPORT_URL`
|
|
593
|
-
- `TESTARO_ID`
|
|
606
|
+
With network watch, the initiator of an interaction is Testaro, not the server. When Testaro is available, it requests a script from a server. If the response is a JSON representation of a script, Testaro runs the script and sends the report to the server.
|
|
594
607
|
|
|
595
|
-
If multiple workstations run Testaro and do work for the same server, each must have a different `
|
|
608
|
+
If multiple workstations run Testaro and do work for the same server, each must have a different value on the `AGENT` environment variable.
|
|
596
609
|
|
|
597
610
|
### Environment variables
|
|
598
611
|
|
|
612
|
+
Variables named above in upper-case letters are environment variables used by various modules.
|
|
613
|
+
|
|
599
614
|
The `text` command can interpolate the value of an environment variable into text that it enters on a page, as documented in the `commands.js` file.
|
|
600
615
|
|
|
601
616
|
Before executing a Testaro script, you can optionally also set the environment variables `DEBUG` (to `'true'` or anything else) and/or `WAITS` (to a non-negative integer). The effects of these variables are described in the `index.js` file.
|
|
602
617
|
|
|
603
|
-
You may store
|
|
618
|
+
You may store environment variables in an untracked `.env` file if you wish, and Testaro will recognize them.
|
|
604
619
|
|
|
605
620
|
## Validation
|
|
606
621
|
|
|
@@ -611,17 +626,15 @@ Testaro and its custom tests can be validated with the _executors_ located in th
|
|
|
611
626
|
The executors are:
|
|
612
627
|
|
|
613
628
|
- `low`: validates low-level invocation
|
|
614
|
-
- `
|
|
615
|
-
- `high2`: validates high-level invocation of a script with a batch
|
|
629
|
+
- `high`: validates high-level invocation of a script
|
|
616
630
|
- `watchDir`: validates directory watching
|
|
617
631
|
- `watchNet`: validates network watching
|
|
618
|
-
- `
|
|
619
|
-
|
|
620
|
-
To validate any single Testaro test `xyz`, enter the statement `npm run test1 xyz`.
|
|
632
|
+
- `test`: validates a Testaro test
|
|
633
|
+
- `tests`: validates all the Testaro tests
|
|
621
634
|
|
|
622
|
-
To validate
|
|
635
|
+
To validate any single Testaro test `xyz`, enter the statement `npm test xyz`.
|
|
623
636
|
|
|
624
|
-
To execute any executor `xyz
|
|
637
|
+
To execute any other executor `xyz`, call it with the statement `node run xyz`.
|
|
625
638
|
|
|
626
639
|
The `tests` executor makes use of the scripts in the `validation/tests/scripts` directory, and they, in turn, run tests on HTML files in the `validation/tests/targets` directory.
|
|
627
640
|
|
|
@@ -651,7 +664,7 @@ The Playwright “Receives Events” actionability check does **not** check whet
|
|
|
651
664
|
|
|
652
665
|
Test packages sometimes do redundant testing, in that two or more packages test for the same issues, although such duplications are not necessarily perfect. This fact creates three problems:
|
|
653
666
|
- One cannot be confident in excluding some tests of some packages on the assumption that they perfectly duplicate tests of other packages.
|
|
654
|
-
- The Testaro report from a script documents each package’s results separately, so a single defect may be documented in multiple locations within the report, making the consumption of the report inefficient.
|
|
667
|
+
- The Testaro report from a script documents each package’s results separately, so a single defect may be documented in multiple locations within the report, making the direct consumption of the report inefficient.
|
|
655
668
|
- An effort to aggregate the results into a single score may distort the scores by inflating the weights of defects that happen to be discovered by multiple packages.
|
|
656
669
|
|
|
657
670
|
The tests provided with Testaro do not exclude any apparently duplicative tests from packages.
|
|
@@ -670,11 +683,14 @@ The files in the `temp` directory are presumed ephemeral and are not tracked by
|
|
|
670
683
|
## Related packages
|
|
671
684
|
|
|
672
685
|
[Testilo](https://www.npmjs.com/package/testilo) is an application that:
|
|
686
|
+
- aims a script at a host by modifying the `url` commands
|
|
673
687
|
- merges batches of hosts into scripts to produce multiple scripts
|
|
674
688
|
- produces scores and adds them to the JSON report files of Testaro
|
|
675
689
|
- produces human-oriented HTML digests from scored reports
|
|
676
690
|
- produces human-oriented HTML reports comparing the scores of hosts
|
|
677
691
|
|
|
692
|
+
Testilo contains procedures that reorganize report data by defect rather than test package, and that compensate for duplicative tests when computing scores.
|
|
693
|
+
|
|
678
694
|
Testaro is derived from [Autotest](https://github.com/jrpool/autotest).
|
|
679
695
|
|
|
680
696
|
Testaro omits some functionalities of Autotest, such as:
|
package/{do.js → call.js}
RENAMED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/*
|
|
2
|
-
|
|
2
|
+
call.js
|
|
3
3
|
Invokes Testaro modules with arguments.
|
|
4
4
|
This is the universal module for use of Testaro from a command line.
|
|
5
5
|
Arguments:
|
|
6
6
|
0. function to execute.
|
|
7
7
|
1+. arguments to pass to the function.
|
|
8
8
|
Usage examples:
|
|
9
|
-
node
|
|
10
|
-
node
|
|
11
|
-
node
|
|
9
|
+
node call high script454
|
|
10
|
+
node call watch dir once 30
|
|
11
|
+
node call watch net forever 60
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
// ########## IMPORTS
|
|
@@ -29,16 +29,16 @@ const reportDir = process.env.REPORTDIR;
|
|
|
29
29
|
// ########## FUNCTIONS
|
|
30
30
|
|
|
31
31
|
// Fulfills a high-level testing request.
|
|
32
|
-
const
|
|
32
|
+
const callHigh = async scriptID => {
|
|
33
33
|
await runJob(scriptID);
|
|
34
34
|
console.log(`Job completed and report ${scriptID}.json saved in ${reportDir}`);
|
|
35
35
|
};
|
|
36
36
|
// Starts a watch.
|
|
37
|
-
const
|
|
37
|
+
const callWatch = async (isDirWatch, isForever, interval) => {
|
|
38
38
|
console.log(
|
|
39
|
-
`Starting a ${isForever ? 'repeating' : 'one-time'} ${isDirWatch ? 'directory' : 'network'} watch`
|
|
39
|
+
`Starting a ${isForever === 'true' ? 'repeating' : 'one-time'} ${isDirWatch === 'true' ? 'directory' : 'network'} watch`
|
|
40
40
|
);
|
|
41
|
-
await cycle(isDirWatch, isForever, interval);
|
|
41
|
+
await cycle(isDirWatch === 'true', isForever === 'true', Number.parseInt(interval, 10));
|
|
42
42
|
console.log('Watching ended');
|
|
43
43
|
};
|
|
44
44
|
|
|
@@ -46,13 +46,13 @@ const doWatch = async (isDirWatch, isForever, interval) => {
|
|
|
46
46
|
|
|
47
47
|
// Execute the requested function.
|
|
48
48
|
if (fn === 'high' && fnArgs.length === 1) {
|
|
49
|
-
|
|
49
|
+
callHigh(fnArgs)
|
|
50
50
|
.then(() => {
|
|
51
51
|
console.log('Execution completed');
|
|
52
52
|
});
|
|
53
53
|
}
|
|
54
54
|
else if (fn === 'watch' && fnArgs.length === 3) {
|
|
55
|
-
|
|
55
|
+
callWatch(... fnArgs)
|
|
56
56
|
.then(() => {
|
|
57
57
|
console.log('Execution completed');
|
|
58
58
|
});
|
package/package.json
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "testaro",
|
|
3
|
-
"version": "8.0.
|
|
3
|
+
"version": "8.0.2",
|
|
4
4
|
"description": "Automation of accessibility testing",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"
|
|
8
|
-
"
|
|
7
|
+
"tests": "node validation/executors/tests",
|
|
8
|
+
"test": "node validation/executors/test",
|
|
9
|
+
"low": "node validation/executors/low",
|
|
10
|
+
"high": "node validation/executors/high",
|
|
11
|
+
"watchDir": "node validation/executors/watchDir",
|
|
12
|
+
"watchNet": "node validation/executors/watchdNet"
|
|
9
13
|
},
|
|
10
14
|
"repository": {
|
|
11
15
|
"type": "git",
|