Repository navigation
Expand file tree
/
Copy pathRushXTerminal.test.ts
More file actions
114 lines (106 loc) · 4.41 KB
/
Copy pathRushXTerminal.test.ts
File metadata and controls
114 lines (106 loc) · 4.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.
import * as fs from 'node:fs';
import * as path from 'node:path';
import { RushXDaemonRequestResolver } from '@rushstack/rush-daemon';
import { RushXDaemonTestFixture } from './RushXDaemonTestFixture';
import { canRunPtyTests, invokeRushxPtyAsync } from './PtyTestProcess';
describe('native Rushx terminal boundaries', () => {
let fixture: RushXDaemonTestFixture;
let cwd: string;
beforeEach(async () => {
fixture = new RushXDaemonTestFixture();
cwd = path.join(fixture.folder, 'projects/a');
fixture.write(
'projects/a/package.json',
JSON.stringify({
name: 'a',
version: '1.0.0',
scripts: { terminal: 'node terminal.cjs', tty: 'node tty.cjs' }
})
);
fixture.write(
'projects/a/terminal.cjs',
'process.stdout.write(JSON.stringify({color:process.env.FORCE_COLOR,width:process.env.COLUMNS}));'
);
fixture.write(
'projects/a/tty.cjs',
`
const fs=require('node:fs');
fs.appendFileSync('tty-runs.txt','run\\n');
fs.writeFileSync('tty.pid',String(process.pid));
if (!process.stdout.isTTY) throw new Error('Expected native stdout terminal.');
if (process.stdin.isTTY) process.stdin.setRawMode(true);
process.on('SIGINT',()=>{
if (process.stdin.isTTY) process.stdin.setRawMode(false);
process.stdout.write('restored='+!!process.stdin.isRaw+'\\n');
process.exit(130);
});
process.stdout.write('raw-ready\\n');
process.stdin.resume();
setInterval(()=>{},1000);
`
);
await fixture.startAsync();
});
afterEach(async () => {
jest.restoreAllMocks();
await fixture[Symbol.asyncDispose]();
});
it('projects terminal color and width after lifecycle preparation without leaking between requests', async () => {
const originalEnvironment: NodeJS.ProcessEnv = { ...process.env };
const environment = fixture.environment({ FORCE_COLOR: undefined, COLUMNS: undefined });
const requests = [
{ isTTY: true, supportsColor: true, columns: 123 },
{ isTTY: true, supportsColor: false, columns: 71 },
{ isTTY: false, supportsColor: false }
].map((terminal) => ({
...fixture.request(['-q', 'terminal'], cwd, environment),
terminal: { ...terminal, acceptsStdin: true }
}));
const results = await Promise.all(requests.map((request) => fixture.runAsync(request)));
expect(results.map((result) => result.exitCode)).toEqual([0, 0, 0]);
expect(results.map((result) => JSON.parse(result.stdout.toString()))).toEqual([
{ color: '1', width: '123' },
{ color: '0', width: '71' },
{}
]);
expect(process.env).toEqual(originalEnvironment);
const explicitEnvironment = fixture.environment({ FORCE_COLOR: '2', COLUMNS: '99' });
expect(await fixture.invokeAsync(false, ['-q', 'terminal'], cwd, explicitEnvironment)).toEqual(
await fixture.invokeAsync(true, ['-q', 'terminal'], cwd, explicitEnvironment)
);
}, 15000);
(canRunPtyTests ? it : it.skip).each([true, false])(
'preserves real PTY raw mode, SIGINT and single execution before daemon admission (TTY stdin: %s)',
async (stdinIsTTY) => {
const resolve = jest.spyOn(RushXDaemonRequestResolver.prototype, 'resolveRequestAsync');
const environment = fixture.environment({ FORCE_COLOR: undefined, COLUMNS: undefined, TERM: 'xterm' });
const native = await invokeRushxPtyAsync(
path.join(path.dirname(require.resolve('@microsoft/rush/package.json')), 'bin/rushx'),
cwd,
environment,
stdinIsTTY
);
expect(native).toMatchObject({ exitCode: 130, restored: true });
expect(native.output).toContain('raw-ready\r\nrestored=false\r\n');
expect(fs.readFileSync(path.join(cwd, 'tty-runs.txt'), 'utf8')).toBe('run\n');
const client = await invokeRushxPtyAsync(
path.resolve(__dirname, '../../bin/rushx-client'),
cwd,
environment,
stdinIsTTY
);
// RUSH_DAEMON=1 asked for the daemon, so the client says why it did not use it.
expect(client).toEqual({
...native,
output:
'rushx-client: the daemon does not run scripts in a terminal; using in-process Rush.\r\n' +
native.output
});
expect(fs.readFileSync(path.join(cwd, 'tty-runs.txt'), 'utf8')).toBe('run\nrun\n');
expect(resolve).not.toHaveBeenCalled();
},
40000
);
});