Skip to content

Commit 2d9318a

Browse files
committed
feat: collpase all jetbrains tests to a single test
1 parent 90d954c commit 2d9318a

9 files changed

Lines changed: 151 additions & 8 deletions

File tree

test/jetbrains/clion/clion.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import fs from 'node:fs/promises';
55
import os from 'node:os';
66
import path from 'node:path';
77

8-
describe('CLion integration tests', async () => {
8+
describe.skipIf(!process.env.JETBRAINS_MANUAL)('CLion integration tests', async () => {
99
const pluginPath = path.resolve('./src/index.ts');
1010

1111
let xdgLine: string | null = null;

test/jetbrains/goland/goland.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import fs from 'node:fs/promises';
55
import os from 'node:os';
66
import path from 'node:path';
77

8-
describe('GoLand integration tests', async () => {
8+
describe.skipIf(!process.env.JETBRAINS_MANUAL)('GoLand integration tests', async () => {
99
const pluginPath = path.resolve('./src/index.ts');
1010

1111
let xdgLine: string | null = null;

test/jetbrains/intellij-idea/intellij-idea.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import fs from 'node:fs/promises';
55
import os from 'node:os';
66
import path from 'node:path';
77

8-
describe('IntelliJ IDEA integration tests', async () => {
8+
describe.skipIf(!process.env.JETBRAINS_MANUAL)('IntelliJ IDEA integration tests', async () => {
99
const pluginPath = path.resolve('./src/index.ts');
1010

1111
let xdgLine: string | null = null;

test/jetbrains/jetbrains.test.ts

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
import { Utils } from '@codifycli/plugin-core';
2+
import { PluginTester, testSpawn } from '@codifycli/plugin-test';
3+
import { expect, describe, it, beforeAll, afterAll } from 'vitest';
4+
import fs from 'node:fs/promises';
5+
import os from 'node:os';
6+
import path from 'node:path';
7+
8+
const PRODUCTS = [
9+
{ type: 'intellij-idea', macAppName: 'IntelliJ IDEA', configPrefix: 'IntelliJIdea', vmoptionsFile: 'idea.vmoptions', linuxCommand: 'intellij-idea-community' },
10+
{ type: 'rider', macAppName: 'Rider', configPrefix: 'Rider', vmoptionsFile: 'rider.vmoptions', linuxCommand: 'rider' },
11+
{ type: 'clion', macAppName: 'CLion', configPrefix: 'CLion', vmoptionsFile: 'clion.vmoptions', linuxCommand: 'clion' },
12+
{ type: 'pycharm', macAppName: 'PyCharm', configPrefix: 'PyCharm', vmoptionsFile: 'pycharm.vmoptions', linuxCommand: 'pycharm-community' },
13+
{ type: 'rustrover', macAppName: 'RustRover', configPrefix: 'RustRover', vmoptionsFile: 'rustrover.vmoptions', linuxCommand: 'rustrover' },
14+
{ type: 'phpstorm', macAppName: 'PhpStorm', configPrefix: 'PhpStorm', vmoptionsFile: 'phpstorm.vmoptions', linuxCommand: 'phpstorm' },
15+
{ type: 'rubymine', macAppName: 'RubyMine', configPrefix: 'RubyMine', vmoptionsFile: 'rubymine.vmoptions', linuxCommand: 'rubymine' },
16+
{ type: 'goland', macAppName: 'GoLand', configPrefix: 'GoLand', vmoptionsFile: 'goland.vmoptions', linuxCommand: 'goland' },
17+
] as const;
18+
19+
const selected = process.env.JETBRAINS_IDE
20+
? (PRODUCTS.find((p) => p.type === process.env.JETBRAINS_IDE) ?? PRODUCTS[0])
21+
: PRODUCTS[Math.floor(Math.random() * PRODUCTS.length)];
22+
23+
console.log(`[JetBrains tests] Selected IDE: ${selected.type}`);
24+
25+
describe(`JetBrains integration tests (${selected.type})`, async () => {
26+
const pluginPath = path.resolve('./src/index.ts');
27+
28+
let xdgLine: string | null = null;
29+
30+
beforeAll(async () => {
31+
if (!Utils.isLinux()) return;
32+
33+
// Wait for unattended-upgrades to release the dpkg lock before running any apt installs.
34+
await testSpawn('systemctl stop unattended-upgrades || true', { requiresRoot: true });
35+
await testSpawn('flock /var/lib/dpkg/lock-frontend true', { requiresRoot: true });
36+
37+
const uid = process.getuid!();
38+
const xdgDir = `/tmp/xdg-runtime-${uid}`;
39+
await fs.mkdir(xdgDir, { recursive: true });
40+
await fs.chmod(xdgDir, 0o700);
41+
process.env.XDG_RUNTIME_DIR = xdgDir;
42+
43+
const bashrc = path.join(os.homedir(), '.bashrc');
44+
const line = `export XDG_RUNTIME_DIR=${xdgDir}`;
45+
const contents = await fs.readFile(bashrc, 'utf8').catch(() => '');
46+
if (!contents.includes(line)) {
47+
await fs.appendFile(bashrc, `\n${line}\n`);
48+
xdgLine = line;
49+
}
50+
});
51+
52+
afterAll(async () => {
53+
if (!xdgLine) return;
54+
55+
const bashrc = path.join(os.homedir(), '.bashrc');
56+
const contents = await fs.readFile(bashrc, 'utf8').catch(() => '');
57+
await fs.writeFile(bashrc, contents.replace(`\n${xdgLine}\n`, ''));
58+
});
59+
60+
it(`Can install ${selected.macAppName}`, { timeout: 600_000 }, async () => {
61+
await PluginTester.fullTest(pluginPath, [{ type: selected.type }], {
62+
validateApply: async () => {
63+
if (Utils.isMacOS()) {
64+
const stat = await fs.lstat(`/Applications/${selected.macAppName}.app`);
65+
expect(stat.isDirectory()).to.be.true;
66+
} else {
67+
const { data } = await testSpawn(`which ${selected.linuxCommand}`);
68+
expect(data?.trim()).to.include(selected.linuxCommand);
69+
}
70+
},
71+
validateDestroy: async () => {
72+
if (Utils.isMacOS()) {
73+
const exists = await fs.access(`/Applications/${selected.macAppName}.app`).then(() => true).catch(() => false);
74+
expect(exists).to.be.false;
75+
} else {
76+
const { data } = await testSpawn(`which ${selected.linuxCommand}`);
77+
expect(data?.trim() ?? '').not.to.include(selected.linuxCommand);
78+
}
79+
},
80+
});
81+
});
82+
83+
it('Can manage JVM heap size', { timeout: 600_000 }, async () => {
84+
const configParent = Utils.isMacOS()
85+
? path.join(os.homedir(), 'Library', 'Application Support', 'JetBrains')
86+
: path.join(os.homedir(), '.config', 'JetBrains');
87+
88+
const findVmOptions = async (): Promise<string | null> => {
89+
try {
90+
const entries = await fs.readdir(configParent);
91+
const dir = entries.filter((e) => e.startsWith(selected.configPrefix)).sort().pop();
92+
if (!dir) return null;
93+
return path.join(configParent, dir, selected.vmoptionsFile);
94+
} catch {
95+
return null;
96+
}
97+
};
98+
99+
await PluginTester.fullTest(pluginPath, [{
100+
type: selected.type,
101+
jvmMaxHeapSize: '2048m',
102+
jvmMinHeapSize: '512m',
103+
}], {
104+
validateApply: async () => {
105+
const vmOptionsPath = await findVmOptions();
106+
expect(vmOptionsPath).to.not.be.null;
107+
const { data } = await testSpawn(`cat "${vmOptionsPath}"`);
108+
expect(data).to.include('-Xmx2048m');
109+
expect(data).to.include('-Xms512m');
110+
},
111+
testModify: {
112+
modifiedConfigs: [{
113+
type: selected.type,
114+
jvmMaxHeapSize: '4096m',
115+
jvmMinHeapSize: '1024m',
116+
}],
117+
validateModify: async () => {
118+
const vmOptionsPath = await findVmOptions();
119+
expect(vmOptionsPath).to.not.be.null;
120+
const { data } = await testSpawn(`cat "${vmOptionsPath}"`);
121+
expect(data).to.include('-Xmx4096m');
122+
expect(data).to.include('-Xms1024m');
123+
},
124+
},
125+
validateDestroy: async () => {
126+
const vmOptionsPath = await findVmOptions();
127+
if (!vmOptionsPath) return;
128+
try {
129+
const content = await fs.readFile(vmOptionsPath, 'utf8');
130+
expect(content).not.to.include('-Xmx');
131+
expect(content).not.to.include('-Xms');
132+
} catch { /* file removed, that's fine */ }
133+
},
134+
});
135+
});
136+
137+
it('Can install plugins', { timeout: 600_000 }, async () => {
138+
await PluginTester.fullTest(pluginPath, [{
139+
type: selected.type,
140+
plugins: ['Docker'],
141+
}]);
142+
});
143+
});

test/jetbrains/phpstorm/phpstorm.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import fs from 'node:fs/promises';
55
import os from 'node:os';
66
import path from 'node:path';
77

8-
describe('PhpStorm integration tests', async () => {
8+
describe.skipIf(!process.env.JETBRAINS_MANUAL)('PhpStorm integration tests', async () => {
99
const pluginPath = path.resolve('./src/index.ts');
1010

1111
let xdgLine: string | null = null;

test/jetbrains/pycharm/pycharm.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import fs from 'node:fs/promises';
55
import os from 'node:os';
66
import path from 'node:path';
77

8-
describe('PyCharm integration tests', async () => {
8+
describe.skipIf(!process.env.JETBRAINS_MANUAL)('PyCharm integration tests', async () => {
99
const pluginPath = path.resolve('./src/index.ts');
1010

1111
let xdgLine: string | null = null;

test/jetbrains/rider/rider.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import fs from 'node:fs/promises';
55
import os from 'node:os';
66
import path from 'node:path';
77

8-
describe('Rider integration tests', async () => {
8+
describe.skipIf(!process.env.JETBRAINS_MANUAL)('Rider integration tests', async () => {
99
const pluginPath = path.resolve('./src/index.ts');
1010

1111
let xdgLine: string | null = null;

test/jetbrains/rubymine/rubymine.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import fs from 'node:fs/promises';
55
import os from 'node:os';
66
import path from 'node:path';
77

8-
describe('RubyMine integration tests', async () => {
8+
describe.skipIf(!process.env.JETBRAINS_MANUAL)('RubyMine integration tests', async () => {
99
const pluginPath = path.resolve('./src/index.ts');
1010

1111
let xdgLine: string | null = null;

test/jetbrains/rustrover/rustrover.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import fs from 'node:fs/promises';
55
import os from 'node:os';
66
import path from 'node:path';
77

8-
describe('RustRover integration tests', async () => {
8+
describe.skipIf(!process.env.JETBRAINS_MANUAL)('RustRover integration tests', async () => {
99
const pluginPath = path.resolve('./src/index.ts');
1010

1111
let xdgLine: string | null = null;

0 commit comments

Comments
 (0)