2
0
mirror of https://github.com/tenrok/axios.git synced 2026-06-17 19:21:29 +03:00

chore: update module test for full check (#7510)

* chore: add additional testing to esm and cjs smoke

* test: updated test suite to include module tests

* fix: esm test smoke import

* fix: cubic feedback

* fix: failing cjs

* fix: cjs timeout
This commit is contained in:
Jay
2026-03-15 21:10:52 +02:00
committed by GitHub
parent 8077435407
commit 76794ac27a
20 changed files with 2999 additions and 1 deletions
+68
View File
@@ -115,3 +115,71 @@ jobs:
- name: Run ESM smoke tests
working-directory: tests/smoke/esm
run: npm run test:smoke:esm:vitest
cjs-module-tests:
name: CJS module tests (Node ${{ matrix.node-version }})
needs: build-and-run-vitest
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node-version: [12, 14, 16, 18]
steps:
- name: Checkout repo
uses: actions/checkout@v6
with:
persist-credentials: true
- name: Setup node
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
cache: npm
cache-dependency-path: tests/module/cjs/package-lock.json
- name: Download npm pack artifact
uses: actions/download-artifact@v8
with:
name: axios-tarball
path: artifacts
- name: Install CJS module test dependencies
working-directory: tests/module/cjs
run: npm install
- name: Install packed axios
working-directory: tests/module/cjs
run: npm install --no-save ../../../artifacts/axios-*.tgz
- name: Run CJS module tests
working-directory: tests/module/cjs
run: npm run test:module:cjs
esm-module-tests:
name: ESM module tests (Node ${{ matrix.node-version }})
needs: build-and-run-vitest
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node-version: [20, 22, 24]
steps:
- name: Checkout repo
uses: actions/checkout@v6
with:
persist-credentials: true
- name: Setup node
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
cache: npm
cache-dependency-path: tests/module/esm/package-lock.json
- name: Download npm pack artifact
uses: actions/download-artifact@v8
with:
name: axios-tarball
path: artifacts
- name: Install ESM module test dependencies
working-directory: tests/module/esm
run: npm install
- name: Install packed axios
working-directory: tests/module/esm
run: npm install --no-save ../../../artifacts/axios-*.tgz
- name: Run ESM module tests
working-directory: tests/module/esm
run: npm run test:module:esm
+5 -1
View File
@@ -54,6 +54,10 @@
"test:vitest:browser": "vitest run --project browser",
"test:vitest:browser:headless": "vitest run --project browser-headless",
"test:vitest:watch": "vitest",
"test:smoke:cjs:vitest": "npm --prefix tests/smoke/cjs run test:smoke:cjs:mocha",
"test:smoke:esm:vitest": "npm --prefix tests/smoke/esm run test:smoke:esm:vitest",
"test:module:cjs": "npm --prefix tests/module/cjs run test:module:cjs",
"test:module:esm": "npm --prefix tests/module/esm run test:module:esm",
"start": "node ./sandbox/server.js",
"examples": "node ./examples/server.js",
"lint": "eslint lib/**/*.js",
@@ -180,4 +184,4 @@
"lint-staged": {
"*.{js,cjs,mjs,ts,json,md,yml,yaml}": "prettier --write"
}
}
}
+1161
View File
File diff suppressed because it is too large Load Diff
+18
View File
@@ -0,0 +1,18 @@
{
"name": "@axios/cjs-module-tests",
"version": "1.0.0",
"description": "CJS module compatibility tests for axios",
"private": true,
"scripts": {
"test:module:cjs": "mocha --timeout 10000 \"tests/**/*.module.test.cjs\""
},
"keywords": [],
"author": "axios team",
"license": "MIT",
"devDependencies": {
"@types/node": "^18.11.3",
"chai": "4.5.0",
"mocha": "9.2.2",
"typescript": "^4.9.5"
}
}
@@ -0,0 +1,44 @@
const assert = require('assert');
const fs = require('fs');
const os = require('os');
const path = require('path');
const { describe, it } = require('mocha');
const { cleanupTempFixture } = require('./helpers/fixture.cjs');
describe('module fixture cleanup helper', () => {
it('removes fixture directories without shelling out to rm', () => {
const fixturePath = fs.mkdtempSync(path.join(os.tmpdir(), 'axios-module-fixture-'));
const nestedPath = path.join(fixturePath, 'nested');
const originalPath = process.env.PATH;
fs.mkdirSync(nestedPath);
fs.writeFileSync(path.join(nestedPath, 'index.ts'), 'export {};\n');
process.env.PATH = '';
try {
cleanupTempFixture(fixturePath);
} finally {
process.env.PATH = originalPath;
}
assert.strictEqual(fs.existsSync(fixturePath), false);
});
it('removes fixture directories when fs.rmSync is unavailable', () => {
const fixturePath = fs.mkdtempSync(path.join(os.tmpdir(), 'axios-module-fixture-legacy-'));
const nestedPath = path.join(fixturePath, 'nested');
const originalRmSync = fs.rmSync;
fs.mkdirSync(nestedPath);
fs.writeFileSync(path.join(nestedPath, 'index.ts'), 'export {};\n');
fs.rmSync = undefined;
try {
cleanupTempFixture(fixturePath);
} finally {
fs.rmSync = originalRmSync;
}
assert.strictEqual(fs.existsSync(fixturePath), false);
});
});
@@ -0,0 +1,32 @@
const fs = require('fs');
const path = require('path');
const createTempFixture = (suiteRoot, name, sourcePath, tsconfig, packageJson) => {
const tempRoot = fs.mkdtempSync(path.join(suiteRoot, `.tmp-module-${name}-`));
const source = fs.readFileSync(sourcePath, 'utf8');
fs.writeFileSync(path.join(tempRoot, 'index.ts'), source);
fs.writeFileSync(path.join(tempRoot, 'tsconfig.json'), JSON.stringify(tsconfig, null, 2));
if (packageJson) {
fs.writeFileSync(path.join(tempRoot, 'package.json'), JSON.stringify(packageJson, null, 2));
}
return tempRoot;
};
const cleanupTempFixture = (dirPath) => {
if (typeof fs.rmSync === 'function') {
fs.rmSync(dirPath, { recursive: true, force: true });
return;
}
if (fs.existsSync(dirPath)) {
fs.rmdirSync(dirPath, { recursive: true });
}
};
module.exports = {
createTempFixture,
cleanupTempFixture,
};
@@ -0,0 +1,41 @@
const { spawnSync } = require('child_process');
const formatCommand = (command, args) => [command].concat(args || []).join(' ');
const runCommand = (command, args, options) => {
const spawnOptions = Object.assign({ encoding: 'utf8' }, options || {});
const result = spawnSync(command, args || [], spawnOptions);
const output = {
code: result.status,
stdout: result.stdout || '',
stderr: result.stderr || '',
command: formatCommand(command, args),
cwd: spawnOptions.cwd || process.cwd(),
};
if (result.error) {
throw result.error;
}
if (output.code !== 0) {
const error = new Error(
[
'Command failed:',
` command: ${output.command}`,
` cwd: ${output.cwd}`,
` exitCode: ${String(output.code)}`,
` stdout:\n${output.stdout}`,
` stderr:\n${output.stderr}`,
].join('\n')
);
error.commandResult = output;
throw error;
}
return output;
};
module.exports = {
runCommand,
};
@@ -0,0 +1,33 @@
const path = require('path');
const { describe, it } = require('mocha');
const { createTempFixture, cleanupTempFixture } = require('./helpers/fixture.cjs');
const { runCommand } = require('./helpers/run-command.cjs');
const suiteRoot = path.resolve(__dirname, '..');
const repoRoot = path.resolve(suiteRoot, '../../..');
const tscBin = path.join(suiteRoot, 'node_modules', 'typescript', 'bin', 'tsc');
const tsconfig = {
compilerOptions: {
target: 'es2016',
module: 'commonjs',
moduleResolution: 'node',
esModuleInterop: true,
strict: true,
skipLibCheck: true,
},
};
describe('module ts-require-default compatibility', () => {
it('compiles and executes require("axios").default imports', () => {
const sourcePath = path.join(repoRoot, 'test/module/ts-require-default/index.ts');
const fixturePath = createTempFixture(suiteRoot, 'ts-require-default', sourcePath, tsconfig);
try {
runCommand('node', [tscBin, '-p', 'tsconfig.json'], { cwd: fixturePath });
runCommand('node', ['index.js'], { cwd: fixturePath });
} finally {
cleanupTempFixture(fixturePath);
}
});
});
@@ -0,0 +1,33 @@
const path = require('path');
const { describe, it } = require('mocha');
const { createTempFixture, cleanupTempFixture } = require('./helpers/fixture.cjs');
const { runCommand } = require('./helpers/run-command.cjs');
const suiteRoot = path.resolve(__dirname, '..');
const repoRoot = path.resolve(suiteRoot, '../../..');
const tscBin = path.join(suiteRoot, 'node_modules', 'typescript', 'bin', 'tsc');
const tsconfig = {
compilerOptions: {
target: 'es2016',
module: 'commonjs',
moduleResolution: 'node',
esModuleInterop: true,
strict: true,
skipLibCheck: true,
},
};
describe('module ts-require compatibility', () => {
it('compiles and executes require("axios") imports', () => {
const sourcePath = path.join(repoRoot, 'test/module/ts-require/index.ts');
const fixturePath = createTempFixture(suiteRoot, 'ts-require', sourcePath, tsconfig);
try {
runCommand('node', [tscBin, '-p', 'tsconfig.json'], { cwd: fixturePath });
runCommand('node', ['index.js'], { cwd: fixturePath });
} finally {
cleanupTempFixture(fixturePath);
}
});
});
@@ -0,0 +1,28 @@
const path = require('path');
const { describe, it } = require('mocha');
const { createTempFixture, cleanupTempFixture } = require('./helpers/fixture.cjs');
const { runCommand } = require('./helpers/run-command.cjs');
const suiteRoot = path.resolve(__dirname, '..');
const repoRoot = path.resolve(suiteRoot, '../../..');
const tscBin = path.join(suiteRoot, 'node_modules', 'typescript', 'bin', 'tsc');
const tsconfig = {
compilerOptions: {
checkJs: true,
module: 'node16',
},
};
describe('module cjs typings compatibility', () => {
it('type-checks commonjs axios typings', () => {
const sourcePath = path.join(repoRoot, 'test/module/typings/cjs/index.ts');
const fixturePath = createTempFixture(suiteRoot, 'typings-cjs', sourcePath, tsconfig);
try {
runCommand('node', [tscBin, '--noEmit', '-p', 'tsconfig.json'], { cwd: fixturePath });
} finally {
cleanupTempFixture(fixturePath);
}
});
});
+1294
View File
File diff suppressed because it is too large Load Diff
+18
View File
@@ -0,0 +1,18 @@
{
"name": "@axios/esm-module-tests",
"version": "1.0.0",
"description": "ESM module compatibility tests for axios",
"private": true,
"type": "module",
"scripts": {
"test:module:esm": "vitest run --config vitest.config.js --project module"
},
"keywords": [],
"author": "axios team",
"license": "MIT",
"devDependencies": {
"@types/node": "^20.0.0",
"typescript": "^4.9.5",
"vitest": "4.1.0"
}
}
@@ -0,0 +1,25 @@
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import { describe, expect, it } from 'vitest';
import { cleanupTempFixture } from './helpers/fixture.js';
describe('module fixture cleanup helper', () => {
it('removes fixture directories without shelling out to rm', () => {
const fixturePath = fs.mkdtempSync(path.join(os.tmpdir(), 'axios-esm-module-fixture-'));
const nestedPath = path.join(fixturePath, 'nested');
const originalPath = process.env.PATH;
fs.mkdirSync(nestedPath);
fs.writeFileSync(path.join(nestedPath, 'index.ts'), 'export {};\n');
process.env.PATH = '';
try {
cleanupTempFixture(fixturePath);
} finally {
process.env.PATH = originalPath;
}
expect(fs.existsSync(fixturePath)).toBe(false);
});
});
+20
View File
@@ -0,0 +1,20 @@
import fs from 'node:fs';
import path from 'node:path';
export const createTempFixture = (suiteRoot, name, sourcePath, tsconfig, packageJson) => {
const tempRoot = fs.mkdtempSync(path.join(suiteRoot, `.tmp-module-${name}-`));
const source = fs.readFileSync(sourcePath, 'utf8');
fs.writeFileSync(path.join(tempRoot, 'index.ts'), source);
fs.writeFileSync(path.join(tempRoot, 'tsconfig.json'), JSON.stringify(tsconfig, null, 2));
if (packageJson) {
fs.writeFileSync(path.join(tempRoot, 'package.json'), JSON.stringify(packageJson, null, 2));
}
return tempRoot;
};
export const cleanupTempFixture = (dirPath) => {
fs.rmSync(dirPath, { recursive: true, force: true });
};
@@ -0,0 +1,35 @@
import { spawnSync } from 'node:child_process';
const formatCommand = (command, args) => [command, ...(args || [])].join(' ');
export const runCommand = (command, args = [], options = {}) => {
const spawnOptions = { encoding: 'utf8', ...options };
const result = spawnSync(command, args, spawnOptions);
const output = {
code: result.status,
stdout: result.stdout || '',
stderr: result.stderr || '',
command: formatCommand(command, args),
cwd: spawnOptions.cwd || process.cwd(),
};
if (result.error) {
throw result.error;
}
if (output.code !== 0) {
throw new Error(
[
'Command failed:',
` command: ${output.command}`,
` cwd: ${output.cwd}`,
` exitCode: ${String(output.code)}`,
` stdout:\n${output.stdout}`,
` stderr:\n${output.stderr}`,
].join('\n')
);
}
return output;
};
+36
View File
@@ -0,0 +1,36 @@
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { describe, it } from 'vitest';
import { createTempFixture, cleanupTempFixture } from './helpers/fixture.js';
import { runCommand } from './helpers/run-command.js';
const suiteRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
const repoRoot = path.resolve(suiteRoot, '../../..');
const tscBin = path.join(suiteRoot, 'node_modules', 'typescript', 'bin', 'tsc');
const tsconfig = {
compilerOptions: {
target: 'es2016',
module: 'commonjs',
moduleResolution: 'node',
esModuleInterop: true,
strict: true,
skipLibCheck: true,
},
};
describe('module ts compatibility', () => {
it('compiles and executes import axios syntax', () => {
const sourcePath = path.join(repoRoot, 'test/module/ts/index.ts');
const fixturePath = createTempFixture(suiteRoot, 'ts', sourcePath, tsconfig, {
type: 'commonjs',
});
try {
runCommand('node', [tscBin, '-p', 'tsconfig.json'], { cwd: fixturePath });
runCommand('node', ['index.js'], { cwd: fixturePath });
} finally {
cleanupTempFixture(fixturePath);
}
});
});
@@ -0,0 +1,31 @@
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { describe, it } from 'vitest';
import { createTempFixture, cleanupTempFixture } from './helpers/fixture.js';
import { runCommand } from './helpers/run-command.js';
const suiteRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
const repoRoot = path.resolve(suiteRoot, '../../..');
const tscBin = path.join(suiteRoot, 'node_modules', 'typescript', 'bin', 'tsc');
const tsconfig = {
compilerOptions: {
checkJs: true,
module: 'node16',
},
};
describe('module esm typings compatibility', () => {
it('type-checks esm axios typings', () => {
const sourcePath = path.join(repoRoot, 'test/module/typings/esm/index.ts');
const fixturePath = createTempFixture(suiteRoot, 'typings-esm', sourcePath, tsconfig, {
type: 'module',
});
try {
runCommand('node', [tscBin, '--noEmit', '-p', 'tsconfig.json'], { cwd: fixturePath });
} finally {
cleanupTempFixture(fixturePath);
}
});
});
+17
View File
@@ -0,0 +1,17 @@
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
testTimeout: 60000,
projects: [
{
test: {
name: 'module',
environment: 'node',
include: ['tests/**/*.module.test.js'],
setupFiles: [],
},
},
],
},
});
@@ -0,0 +1,23 @@
const axios = require('axios');
const { describe, it } = require('mocha');
const { expect } = require('chai');
const { CanceledError, AxiosError, AxiosHeaders } = axios;
describe('CommonJS importing', () => {
it('should import axios', () => {
expect(typeof axios).to.be.equal('function');
});
it('should import CanceledError', () => {
expect(typeof CanceledError).to.be.equal('function');
});
it('should import AxiosError', () => {
expect(typeof AxiosError).to.be.equal('function');
});
it('should import AxiosHeaders', () => {
expect(typeof AxiosHeaders).to.be.equal('function');
});
});
@@ -0,0 +1,37 @@
import { describe, expect, it } from 'vitest';
import axios, { CanceledError, AxiosError, AxiosHeaders } from 'axios';
import settle from 'axios/unsafe/core/settle.js';
describe('ESM importing', () => {
it('should import axios', () => {
expect(typeof axios).toStrictEqual('function');
});
it('should import CanceledError', () => {
expect(typeof CanceledError).toStrictEqual('function');
});
it('should import AxiosError', () => {
expect(typeof AxiosError).toStrictEqual('function');
});
it('should import AxiosHeaders', () => {
expect(typeof AxiosHeaders).toStrictEqual('function');
});
it('should import settle', () => {
expect(typeof settle).toStrictEqual('function');
});
it('should import CanceledError from axios', () => {
expect(axios.CanceledError).toStrictEqual(CanceledError);
});
it('should import AxiosError from axios', () => {
expect(axios.AxiosError).toStrictEqual(AxiosError);
});
it('should import AxiosHeaders from axios', () => {
expect(axios.AxiosHeaders).toStrictEqual(AxiosHeaders);
});
});