1 | const { spawn } = require('child_process');
|
2 | const fs = require('fs-extra');
|
3 | const path = require('path');
|
4 |
|
5 | const KeySymbol = {
|
6 | DOWN: '\x1B\x5B\x42',
|
7 | UP: '\x1B\x5B\x41',
|
8 | ENTER: '\x0D',
|
9 | SPACE: '\x20'
|
10 | };
|
11 |
|
12 | const MockServerPort = {
|
13 | SMAPI: 4010,
|
14 | LWA: 4011
|
15 | };
|
16 |
|
17 | const tempDirectory = path.join(process.cwd(), 'test/temp');
|
18 |
|
19 | const resetTempDirectory = () => {
|
20 | fs.ensureDirSync(tempDirectory);
|
21 | fs.emptyDirSync(tempDirectory);
|
22 | };
|
23 |
|
24 | const getPathInTempDirectory = (folderPath) => path.join(tempDirectory, folderPath);
|
25 |
|
26 | const makeFolderInTempDirectory = (folderPath) => {
|
27 | fs.ensureDirSync(getPathInTempDirectory(folderPath));
|
28 | };
|
29 |
|
30 | const run = (cmd, args, options = {}) => {
|
31 | const inputs = options.inputs || [];
|
32 | const parse = options.parse || false;
|
33 | const returnProcessHandle = options.returnProcessHandle || false;
|
34 | const cwd = options.cwd || tempDirectory;
|
35 | const env = { ...process.env, ...options.env };
|
36 |
|
37 | fs.ensureDirSync(cwd);
|
38 |
|
39 | const childProcess = spawn(cmd, args, { cwd, env, stdio: [null, null, null, 'ipc'] });
|
40 |
|
41 | return new Promise((resolve, reject) => {
|
42 | let output = '';
|
43 | let errorMessage = '';
|
44 | const processStream = (data, isError = false) => {
|
45 | const dataStr = data.toString();
|
46 | if (isError) {
|
47 | errorMessage += dataStr;
|
48 | } else {
|
49 | output += dataStr;
|
50 | }
|
51 | if (process.env.DEBUG) {
|
52 | console.log(dataStr);
|
53 | }
|
54 | return dataStr;
|
55 | };
|
56 | const processData = (data) => processStream(data);
|
57 | const processError = (data) => processStream(data, true);
|
58 |
|
59 | childProcess.stdout.on('data', (data) => {
|
60 | const dataStr = processData(data);
|
61 |
|
62 | const index = inputs.findIndex(i => dataStr.includes(i.match));
|
63 | if (index > -1) {
|
64 | const { input } = inputs[index];
|
65 | inputs.splice(index, 1);
|
66 | const value = input ? `${input}${KeySymbol.ENTER}` : KeySymbol.ENTER;
|
67 | childProcess.stdin.write(value);
|
68 | }
|
69 | if (returnProcessHandle && inputs.length === 0) {
|
70 | resolve(childProcess);
|
71 | }
|
72 | });
|
73 |
|
74 | childProcess.stderr.on('data', (data) => {
|
75 | errorMessage = processError(data);
|
76 | });
|
77 |
|
78 | childProcess.on('close', (code) => {
|
79 | if (code) {
|
80 | reject(new Error(`${output}${errorMessage}`));
|
81 | } else {
|
82 | output = parse ? JSON.parse(output) : output;
|
83 | resolve(output);
|
84 | }
|
85 | });
|
86 | });
|
87 | };
|
88 |
|
89 | const _startMockServer = async (port, swaggerSpecPath) => {
|
90 | const inputs = [
|
91 | { match: 'Prism is listening on' }
|
92 | ];
|
93 | const args = ['run', 'prism', '--', 'mock', '-p', port, swaggerSpecPath];
|
94 | const options = { returnProcessHandle: true, inputs, cwd: process.cwd() };
|
95 | return run('npm', args, options);
|
96 | };
|
97 |
|
98 | const startMockSmapiServer = () => _startMockServer(MockServerPort.SMAPI, 'node_modules/ask-smapi-model/spec.json');
|
99 | const startMockLwaServer = () => _startMockServer(MockServerPort.LWA, 'test/integration/fixtures/lwa-swagger.json');
|
100 |
|
101 | module.exports = {
|
102 | KeySymbol,
|
103 | getPathInTempDirectory,
|
104 | makeFolderInTempDirectory,
|
105 | resetTempDirectory,
|
106 | run,
|
107 | startMockSmapiServer,
|
108 | startMockLwaServer,
|
109 | MockServerPort
|
110 | };
|