Skip to content
This repository was archived by the owner on Aug 7, 2023. It is now read-only.

Commit 9cd63ce

Browse files
test: add CI-only tests
1 parent 53f4841 commit 9cd63ce

File tree

12 files changed

+460
-149
lines changed

12 files changed

+460
-149
lines changed

.github/workflows/CI.yml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,51 @@ jobs:
2626
- uses: actions/setup-node@v3
2727
with:
2828
node-version: ${{ matrix.node_version }}
29+
- uses: volta-cli/[email protected]
30+
- name: Install multiple Node versions
31+
if: runner.os != 'Windows'
32+
run: |
33+
volta install node@10
34+
echo "NODE_10=$(volta which node)" >> $GITHUB_ENV
35+
echo "NODE_10_VERSION=$(node --version)" >> $GITHUB_ENV
36+
volta install node@latest
37+
echo "NODE_LATEST=$(volta which node)" >> $GITHUB_ENV
38+
echo "NODE_LATEST_VERSION=$(node --version)" >> $GITHUB_ENV
39+
volta install node@16
40+
echo "NODE_DEFAULT=$(volta which node)" >> $GITHUB_ENV
41+
echo "NODE_DEFAULT_VERSION=$(node --version)" >> $GITHUB_ENV
42+
- name: Install multiple Node versions (Windows)
43+
if: runner.os == 'Windows'
44+
run: |
45+
volta install node@10
46+
echo "NODE_10=$(volta which node)" >> $env:GITHUB_ENV
47+
echo "NODE_10_VERSION=$(node --version)" >> $env:GITHUB_ENV
48+
volta install node@latest
49+
echo "NODE_LATEST=$(volta which node)" >> $env:GITHUB_ENV
50+
echo "NODE_LATEST_VERSION=$(node --version)" >> $env:GITHUB_ENV
51+
volta install node@16
52+
echo "NODE_DEFAULT=$(volta which node)" >> $env:GITHUB_ENV
53+
echo "NODE_DEFAULT_VERSION=$(node --version)" >> $env:GITHUB_ENV
54+
- name: Setup dummy ESLint projects
55+
run: |
56+
mkdir ~/with-eslint-6 && cd ~/with-eslint-6
57+
npm init --yes
58+
npm install eslint@6
59+
cd ..
60+
61+
mkdir ~/with-eslint-7 && cd ~/with-eslint-7
62+
npm init --yes
63+
npm install eslint@7
64+
cd ..
65+
66+
mkdir ~/with-eslint-latest && cd ~/with-eslint-latest
67+
npm init --yes
68+
npm install eslint@latest
69+
cd ..
2970
- name: Install dependencies
3071
run: |
3172
apm install
73+
apm install linter-eslint
3274
# ./node_modules/.bin/atom-package-deps .
3375
3476
- name: Run tests 👩🏾‍💻

lib/job-manager.js

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,11 @@ class JobManager {
5757

5858
let nodeBin = Config.get('nodeBin');
5959
console.debug('JobManager creating worker at:', nodeBin);
60-
this.killWorker();
60+
61+
// TODO: Figure out if this can even happen anymore.
62+
if (this.worker) {
63+
this.killWorker(this.worker);
64+
}
6165

6266
// We choose to do a sync test here because this method is much easier to
6367
// reason about without an `await` keyword introducing side effects.
@@ -99,32 +103,37 @@ class JobManager {
99103
this.worker.stderr
100104
.pipe(ndjson.parse())
101105
.on('data', this.receiveError.bind(this));
102-
103-
this.worker.on('close', () => {
104-
if (this.worker.killed === false) {
105-
this.createWorker();
106-
}
107-
});
108106
});
109107

108+
let nullWorkerPromise = () => {
109+
this._workerPromise = null;
110+
};
111+
110112
this._workerPromise = promise;
111113
this._workerPromise
112-
.then(() => this._workerPromise = null)
113-
.catch(() => this._workerPromise = null);
114+
.then(nullWorkerPromise)
115+
.catch(nullWorkerPromise);
114116

115117
return promise;
116118
}
117119

118-
suspend () {
119-
console.warn('Suspending worker');
120-
this.killWorker();
121-
this.worker = null;
120+
async suspend () {
121+
console.debug('Suspending worker');
122+
// To prevent async chaos, we should refrain from killing a worker that we're in the process of
123+
let promise = this._workerPromise || Promise.resolve();
124+
this._killingWorkerPromise = promise.then(() => {
125+
let worker = this.worker;
126+
this.worker = null;
127+
this.killWorker(worker);
128+
this._killingWorkerPromise = null;
129+
});
130+
return this._killingWorkerPromise;
122131
}
123132

124-
killWorker () {
125-
if (!this.worker || this.worker.exitCode) { return; }
126-
this.worker.removeAllListeners();
127-
this.worker.kill();
133+
killWorker (worker) {
134+
if (!worker || worker.exitCode) { return; }
135+
worker.removeAllListeners();
136+
worker.kill();
128137
}
129138

130139
ensureWorker () {
@@ -170,8 +179,12 @@ class JobManager {
170179
}
171180

172181
async send (bundle) {
182+
if (this._killingWorkerPromise) {
183+
console.debug('Waiting for worker to be killed');
184+
await this._killingWorkerPromise;
185+
}
173186
if (!this.worker) {
174-
console.warn('Creating worker');
187+
console.debug('Creating worker');
175188
await this.createWorker();
176189
}
177190

lib/main.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export default {
5555
},
5656

5757
isLegacyPackagePresent () {
58-
return ('linter-eslint' in atom.packages.activePackages);
58+
return atom.packages.isPackageActive('linter-eslint');
5959
},
6060

6161
async activate () {
@@ -132,11 +132,11 @@ export default {
132132

133133
if (config.nodeBin !== prevConfig.nodeBin) {
134134
this.notified.invalidNodeBin = false;
135+
this.jobManager.suspend();
135136
NodePathTester
136137
.test(config.nodeBin)
137138
.then((version) => {
138-
console.log(`Switched Node to version:`, version);
139-
this.jobManager.suspend();
139+
console.info(`Switched Node to version:`, version);
140140
})
141141
.catch(() => {
142142
this.sleep();
@@ -249,8 +249,8 @@ export default {
249249
// Show a bunch of stuff to the user that can help them figure out why the
250250
// package isn't behaving the way they think it ought to, or else give them
251251
// something to copy and paste into a new issue.
252-
async debugJob () {
253-
const textEditor = atom.workspace.getActiveTextEditor();
252+
async debugJob (editor = null) {
253+
const textEditor = editor || atom.workspace.getActiveTextEditor();
254254
let filePath = 'unknown', editorScopes = ['unknown'];
255255
if (atom.workspace.isTextEditor(textEditor)) {
256256
filePath = textEditor.getPath();
@@ -328,7 +328,7 @@ export default {
328328
}
329329
} catch (error) {
330330
atom.notifications.addError(`${error}`, { dismissable: true });
331-
return;
331+
return {};
332332
}
333333

334334
let whichPackageWillLint;
@@ -339,6 +339,7 @@ export default {
339339
} else {
340340
whichPackageWillLint = 'linter-eslint-node';
341341
}
342+
debug.whichPackageWillLint = whichPackageWillLint;
342343

343344
let debugMessage = [
344345
`Atom version: ${debug.atomVersion}`,

lib/worker.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ const MINIMUM_ESLINT_VERSION = '7.0.0';
1616
const PATHS_CACHE = new Map();
1717
const ESLINT_CACHE = new Map();
1818

19-
// TODO: There must be some cases where this logic is too naive, right?
2019
function descendsFrom (filePath, projectPath) {
2120
if (typeof filePath !== 'string') { return false; }
2221
return filePath.startsWith(projectPath.endsWith(Path.sep) ? projectPath : `${projectPath}${Path.sep}`);
@@ -414,7 +413,7 @@ async function processMessage (bundle) {
414413
return;
415414
}
416415
error.key = key;
417-
error.error = 'Unknown error';
416+
error.error = error.message || 'Unknown error';
418417
emitError(
419418
JSON.stringify(error, Object.getOwnPropertyNames(error))
420419
);

spec/.eslintrc.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,8 @@ module.exports = {
22
env: {
33
jasmine: true,
44
atomtest: true
5+
},
6+
globals: {
7+
pass: 'readonly'
58
}
69
};
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
root: true,
3+
rules: {
4+
"no-unused-vars": "error"
5+
}
6+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
function unusedFunction () {
3+
// no-op
4+
}

spec/helpers.js

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,31 @@ export async function openAndSetProjectDir (fileName, projectDir) {
3838
let editor = await atom.workspace.open(fileName);
3939
atom.project.setPaths([projectDir]);
4040
await race(
41-
atom.project.watcherPromisesByPath[projectDir],
41+
atom.project.getWatcherPromise(projectDir),
4242
wait(1000)
4343
);
4444
return editor;
4545
}
4646

47+
export function getNotification (expectedMessage = null) {
48+
let promise = new Promise((resolve, reject) => {
49+
let notificationSub;
50+
let newNotification = notification => {
51+
if (expectedMessage && notification.getMessage()) {
52+
return;
53+
}
54+
if (notificationSub !== undefined) {
55+
notificationSub.dispose();
56+
resolve(notification);
57+
} else {
58+
reject();
59+
}
60+
};
61+
notificationSub = atom.notifications.onDidAddNotification(newNotification);
62+
});
63+
return race(promise, wait(3000));
64+
}
65+
4766
// Grab this before it gets wrapped.
4867
const _setTimeout = window.setTimeout;
4968
export function wait (ms) {

0 commit comments

Comments
 (0)