├── __tests__ ├── lib │ ├── mocks │ │ ├── .hoge │ │ ├── search │ │ │ ├── empty.ts │ │ │ └── _userName@string.ts │ │ ├── collections │ │ │ ├── .sample │ │ │ └── entries.json.ts │ │ ├── @utils │ │ │ └── index.ts │ │ ├── @types.ts │ │ ├── index.ts │ │ ├── users │ │ │ ├── self.ts │ │ │ ├── _userId.ts │ │ │ └── index.ts │ │ ├── $mock.js │ │ └── $mock.ts │ └── index.spec.ts ├── units.spec.ts └── index.spec.ts ├── .vscode ├── extensions.json └── settings.json ├── bin └── index.js ├── tsconfig.build.json ├── examples ├── node │ ├── nodemon.json │ ├── src │ │ └── index.js │ ├── mocks │ │ └── users │ │ │ └── _userId.js │ ├── README.md │ └── package.json ├── with-nuxtjs │ ├── plugins │ │ └── mock.js │ ├── nuxt.config.js │ ├── mocks │ │ └── users │ │ │ └── _userId.js │ ├── pages │ │ └── index.vue │ ├── jsconfig.json │ ├── README.md │ └── package.json ├── with-typescript │ ├── nodemon.json │ ├── tsconfig.json │ ├── src │ │ └── index.ts │ ├── mocks │ │ └── users │ │ │ └── _userId.ts │ ├── README.md │ └── package.json └── browser │ ├── public │ └── index.html │ ├── mocks │ └── users │ │ └── _userId.js │ ├── webpack.config.js │ ├── src │ └── index.js │ ├── README.md │ └── package.json ├── devConfigs ├── .js.rc └── .ts.rc ├── src ├── settle.d.ts ├── lib │ ├── getInputs.ts │ ├── watchInputDir.ts │ ├── writeRouteFile.ts │ ├── listFiles.ts │ ├── getConfig.ts │ ├── cli.ts │ ├── buildRouteFile.ts │ └── createRouteString.ts ├── asyncResponse.ts ├── findHandler.ts ├── createRelativePath.ts ├── untransformData.ts ├── compositeParams.ts ├── createValues.ts ├── createLogString.ts ├── index.ts ├── makeResponse.ts ├── types.ts ├── findAndCallHandler.ts └── MockServer.ts ├── .editorconfig ├── jest.config.js ├── .versionrc.json ├── .github ├── pull_request_template.md ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── dependabot.yml └── workflows │ └── nodejs.yml ├── tsconfig.json ├── LICENSE ├── .gitignore ├── package.json ├── CHANGELOG.md ├── docs └── ja │ └── README.md └── README.md /__tests__/lib/mocks/.hoge: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /__tests__/lib/mocks/search/empty.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /__tests__/lib/mocks/collections/.sample: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /__tests__/lib/mocks/@utils/index.ts: -------------------------------------------------------------------------------- 1 | export const testFn = () => 'Hello!' 2 | -------------------------------------------------------------------------------- /__tests__/lib/mocks/@types.ts: -------------------------------------------------------------------------------- 1 | export interface Sample { 2 | id: number 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["dbaeumer.vscode-eslint"] 3 | } 4 | -------------------------------------------------------------------------------- /bin/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | require('../dist/lib/cli').run(process.argv.slice(2)) 3 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["src/**/*"] 4 | } 5 | -------------------------------------------------------------------------------- /examples/node/nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "exec": "node src/index.js", 3 | "watch": ["src", "mocks"] 4 | } 5 | -------------------------------------------------------------------------------- /devConfigs/.js.rc: -------------------------------------------------------------------------------- 1 | { 2 | "input": "__tests__/lib/mocks", 3 | "target": "cjs", 4 | "outputExt": "js" 5 | } 6 | -------------------------------------------------------------------------------- /devConfigs/.ts.rc: -------------------------------------------------------------------------------- 1 | { 2 | "input": "__tests__/lib/mocks", 3 | "target": "es6", 4 | "outputExt": "ts" 5 | } 6 | -------------------------------------------------------------------------------- /examples/with-nuxtjs/plugins/mock.js: -------------------------------------------------------------------------------- 1 | import mock from '~/mocks/$mock.js' 2 | 3 | export default ({ $axios }) => { 4 | mock($axios) 5 | } 6 | -------------------------------------------------------------------------------- /examples/with-typescript/nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "exec": "tsc && node dist/src/index.js", 3 | "ext": "ts", 4 | "watch": ["src", "mocks"] 5 | } 6 | -------------------------------------------------------------------------------- /examples/with-nuxtjs/nuxt.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | mode: 'spa', 3 | modules: ['@nuxtjs/axios'], 4 | plugins: ['~/plugins/mock.js'] 5 | } 6 | -------------------------------------------------------------------------------- /__tests__/lib/mocks/index.ts: -------------------------------------------------------------------------------- 1 | import { MockMethods } from '~/src/types' 2 | 3 | export default { 4 | get: () => [200, 'Hello world!'] 5 | } as MockMethods 6 | -------------------------------------------------------------------------------- /examples/browser/public/index.html: -------------------------------------------------------------------------------- 1 | Examples - axios-mock-server 2 |

browser

3 | 4 | 5 | -------------------------------------------------------------------------------- /__tests__/lib/mocks/users/self.ts: -------------------------------------------------------------------------------- 1 | import { MockMethods } from '~/src/types' 2 | import { users } from './index' 3 | 4 | export default { get: () => [200, users[0]] } as MockMethods 5 | -------------------------------------------------------------------------------- /src/settle.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'axios/lib/core/settle' { 2 | const settle: (resolve: (res: any) => void, reject: (reason: any) => void, res: any) => void 3 | export = settle 4 | } 5 | -------------------------------------------------------------------------------- /examples/with-typescript/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "outDir": "dist", 5 | "strict": true, 6 | "target": "esnext" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/lib/getInputs.ts: -------------------------------------------------------------------------------- 1 | import { defaultConfig } from './getConfig' 2 | 3 | export default (input?: string | string[]) => 4 | Array.isArray(input) ? input : [input || defaultConfig.input] 5 | -------------------------------------------------------------------------------- /examples/node/src/index.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios') 2 | require('../mocks/$mock')() 3 | 4 | axios.get('https://example.com/users/0').then(({ data }) => { 5 | console.log(data) 6 | }) 7 | -------------------------------------------------------------------------------- /examples/node/mocks/users/_userId.js: -------------------------------------------------------------------------------- 1 | const users = [{ id: 0, name: 'foo' }] 2 | 3 | module.exports = { 4 | get({ values }) { 5 | return [200, users.find(user => user.id === values.userId)] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /examples/browser/mocks/users/_userId.js: -------------------------------------------------------------------------------- 1 | const users = [{ id: 0, name: 'foo' }] 2 | 3 | export default { 4 | get({ values }) { 5 | return [200, users.find(user => user.id === values.userId)] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /examples/with-nuxtjs/mocks/users/_userId.js: -------------------------------------------------------------------------------- 1 | const users = [{ id: 0, name: 'foo' }] 2 | 3 | export default { 4 | get({ values }) { 5 | return [200, users.find(user => user.id === values.userId)] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /examples/with-nuxtjs/pages/index.vue: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "eslint.run": "onSave", 3 | "editor.codeActionsOnSave": { 4 | "source.fixAll.eslint": true 5 | }, 6 | "files.associations": { 7 | ".mockserverrc": "json" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/asyncResponse.ts: -------------------------------------------------------------------------------- 1 | import { MockResponse } from './types' 2 | 3 | export default async ( 4 | status: number, 5 | query: Promise, 6 | headers?: any 7 | ): Promise => [status, await query, headers] 8 | -------------------------------------------------------------------------------- /__tests__/lib/mocks/users/_userId.ts: -------------------------------------------------------------------------------- 1 | import { MockMethods } from '~/src/types' 2 | import { users } from './index' 3 | 4 | export default { 5 | get: ({ values }) => [200, users.filter(user => user.id === values.userId)[0]] 6 | } as MockMethods 7 | -------------------------------------------------------------------------------- /examples/browser/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | module.exports = { 4 | devServer: { 5 | contentBase: path.resolve(__dirname, 'public'), 6 | hot: true, 7 | port: 3000, 8 | watchContentBase: true 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /__tests__/lib/mocks/search/_userName@string.ts: -------------------------------------------------------------------------------- 1 | import { MockMethods } from '~/src/types' 2 | import { users } from '../users/index' 3 | 4 | export default { 5 | get: ({ values }) => [200, users.filter(user => user.name === values.userName)[0]] 6 | } as MockMethods 7 | -------------------------------------------------------------------------------- /examples/with-typescript/src/index.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | // @ts-ignore: Cannot find module 4 | import mock from '../mocks/$mock' 5 | 6 | mock() 7 | 8 | axios.get('https://example.com/users/0').then(({ data }) => { 9 | console.log(data) 10 | }) 11 | -------------------------------------------------------------------------------- /__tests__/lib/mocks/collections/entries.json.ts: -------------------------------------------------------------------------------- 1 | import { MockMethods } from '~/src/types' 2 | 3 | export const entries = [ 4 | { id: 0, title: 'aaa' }, 5 | { id: 1, title: 'bbb' } 6 | ] 7 | 8 | export default { 9 | get: () => [200, entries] 10 | } as MockMethods 11 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_size = 2 8 | indent_style = space 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /src/lib/watchInputDir.ts: -------------------------------------------------------------------------------- 1 | import chokidar from 'chokidar' 2 | import { mockFileRegExp } from './getConfig' 3 | 4 | export default (input: string, callback: (...args: any) => void) => { 5 | chokidar.watch(input, { ignoreInitial: true, ignored: mockFileRegExp }).on('all', callback) 6 | } 7 | -------------------------------------------------------------------------------- /examples/with-nuxtjs/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "paths": { 5 | "~/*": ["./*"], 6 | "@/*": ["./*"], 7 | "~~/*": ["./*"], 8 | "@@/*": ["./*"] 9 | } 10 | }, 11 | "exclude": ["node_modules", ".nuxt", "dist"] 12 | } 13 | -------------------------------------------------------------------------------- /src/findHandler.ts: -------------------------------------------------------------------------------- 1 | import { HandlersSet, HttpMethod } from './types' 2 | 3 | export default (method = '', relativePath: string, handlersSet: HandlersSet) => { 4 | const handlers = handlersSet[method.toLowerCase() as HttpMethod] 5 | 6 | if (handlers) return handlers.find(([regPath]) => regPath.test(relativePath)) 7 | } 8 | -------------------------------------------------------------------------------- /src/lib/writeRouteFile.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | 3 | export default ({ filePath, text }: { filePath: string; text: string }) => { 4 | if (fs.existsSync(filePath) && fs.readFileSync(filePath, 'utf8') === text) return 5 | 6 | fs.writeFileSync(filePath, text, 'utf8') 7 | console.log(`${filePath} was built successfully.`) 8 | } 9 | -------------------------------------------------------------------------------- /examples/with-typescript/mocks/users/_userId.ts: -------------------------------------------------------------------------------- 1 | import { MockMethods } from 'axios-mock-server' 2 | 3 | const users = [{ id: 0, name: 'foo' }] 4 | 5 | const mockMethods: MockMethods = { 6 | get({ values }) { 7 | return [200, users.find(user => user.id === values.userId)] 8 | } 9 | } 10 | 11 | export default mockMethods 12 | -------------------------------------------------------------------------------- /examples/browser/src/index.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import mock from '../mocks/$mock' 3 | 4 | mock() 5 | 6 | const button = document.querySelector('button') 7 | 8 | button.addEventListener('click', async () => { 9 | const { data } = await axios.get('https://example.com/users/0') 10 | alert(JSON.stringify(data)) 11 | }) 12 | -------------------------------------------------------------------------------- /src/lib/listFiles.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import path from 'path' 3 | 4 | export const listFiles = (targetDir: string): string[] => 5 | fs.readdirSync(targetDir, { withFileTypes: true }).flatMap(dirent => { 6 | const target = path.posix.join(targetDir, dirent.name) 7 | return dirent.isFile() ? [target] : listFiles(target) 8 | }) 9 | -------------------------------------------------------------------------------- /src/createRelativePath.ts: -------------------------------------------------------------------------------- 1 | const regOriginURL = /^(https?:)?\/\/[^/]+/ 2 | 3 | export default (url = '', baseURL?: string) => 4 | `/${url 5 | .replace( 6 | baseURL && url.startsWith(baseURL) ? baseURL : regOriginURL.test(url) ? regOriginURL : '', 7 | '' 8 | ) 9 | .replace(/^\//, '') 10 | .replace(/\/$/, '')}` 11 | -------------------------------------------------------------------------------- /examples/node/README.md: -------------------------------------------------------------------------------- 1 | # Node.js 2 | 3 | ## How to use 4 | 5 | Download the example: 6 | 7 | ```sh 8 | $ curl https://codeload.github.com/solufa/axios-mock-server/tar.gz/develop | tar -xzo --no-same-permissions --strip=2 axios-mock-server-develop/examples/node 9 | $ cd node 10 | ``` 11 | 12 | Install it and start development: 13 | 14 | ```sh 15 | $ npm install 16 | $ npm run dev 17 | ``` 18 | -------------------------------------------------------------------------------- /examples/browser/README.md: -------------------------------------------------------------------------------- 1 | # Browser 2 | 3 | ## How to use 4 | 5 | Download the example: 6 | 7 | ```sh 8 | $ curl https://codeload.github.com/solufa/axios-mock-server/tar.gz/develop | tar -xzo --no-same-permissions --strip=2 axios-mock-server-develop/examples/browser 9 | $ cd browser 10 | ``` 11 | 12 | Install it and start development: 13 | 14 | ```sh 15 | $ npm install 16 | $ npm run dev 17 | ``` 18 | -------------------------------------------------------------------------------- /src/untransformData.ts: -------------------------------------------------------------------------------- 1 | export default (data: any, headers: any) => { 2 | const contentType: string | undefined = headers['Content-Type'] || headers['content-type'] 3 | 4 | if (contentType) { 5 | if (/^application\/json/.test(contentType)) return JSON.parse(data) 6 | if (/^application\/x-www-form-urlencoded/.test(contentType)) return new URLSearchParams(data) 7 | } 8 | 9 | return data 10 | } 11 | -------------------------------------------------------------------------------- /examples/with-nuxtjs/README.md: -------------------------------------------------------------------------------- 1 | # With Nuxt.js 2 | 3 | ## How to use 4 | 5 | Download the example: 6 | 7 | ```sh 8 | $ curl https://codeload.github.com/solufa/axios-mock-server/tar.gz/develop | tar -xzo --no-same-permissions --strip=2 axios-mock-server-develop/examples/with-nuxtjs 9 | $ cd with-nuxtjs 10 | ``` 11 | 12 | Install it and start development: 13 | 14 | ```sh 15 | $ npm install 16 | $ npm run dev 17 | ``` 18 | -------------------------------------------------------------------------------- /examples/with-typescript/README.md: -------------------------------------------------------------------------------- 1 | # With TypeScript 2 | 3 | ## How to use 4 | 5 | Download the example: 6 | 7 | ```sh 8 | $ curl https://codeload.github.com/solufa/axios-mock-server/tar.gz/develop | tar -xzo --no-same-permissions --strip=2 axios-mock-server-develop/examples/with-typescript 9 | $ cd with-typescript 10 | ``` 11 | 12 | Install it and start development: 13 | 14 | ```sh 15 | $ npm install 16 | $ npm run dev 17 | ``` 18 | -------------------------------------------------------------------------------- /__tests__/lib/mocks/users/index.ts: -------------------------------------------------------------------------------- 1 | import { MockMethods } from '~/src/types' 2 | 3 | export const users = [ 4 | { id: 0, name: 'aaa' }, 5 | { id: 1, name: '123' } 6 | ] 7 | 8 | export default { 9 | get: () => [200, users], 10 | post: ({ data }) => { 11 | const user = { 12 | id: users.length, 13 | name: data.name 14 | } 15 | 16 | users.push(user) 17 | 18 | return [201, user] 19 | } 20 | } as MockMethods 21 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | const { pathsToModuleNameMapper } = require('ts-jest/utils') 2 | const { compilerOptions } = require('./tsconfig') 3 | 4 | module.exports = { 5 | preset: 'ts-jest', 6 | testEnvironment: 'node', 7 | watchPathIgnorePatterns: ['/examples/'], 8 | testPathIgnorePatterns: ['/__tests__/lib/mocks/'], 9 | moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, { 10 | prefix: '/' 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /src/compositeParams.ts: -------------------------------------------------------------------------------- 1 | export default ( 2 | query: string | undefined, 3 | configParams: { [key: string]: any } 4 | ): { [key: string]: any } => { 5 | const searchParams = new URLSearchParams(query) 6 | const searchObject = [...searchParams].reduce( 7 | (prev, current) => ({ 8 | ...prev, 9 | [current[0]]: isNaN(+current[1]) ? current[1] : +current[1] 10 | }), 11 | {} 12 | ) 13 | 14 | return { 15 | ...searchObject, 16 | ...configParams 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node", 3 | "private": true, 4 | "scripts": { 5 | "dev": "npm-run-all mock:build --parallel watch mock:watch", 6 | "watch": "nodemon", 7 | "mock:build": "axios-mock-server --build", 8 | "mock:watch": "axios-mock-server --watch" 9 | }, 10 | "dependencies": { 11 | "axios": "^0.19.0" 12 | }, 13 | "devDependencies": { 14 | "axios-mock-server": "latest", 15 | "nodemon": "^1.19.2", 16 | "npm-run-all": "^4.1.5" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/with-nuxtjs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "with-nuxtjs", 3 | "private": true, 4 | "scripts": { 5 | "dev": "npm-run-all mock:build --parallel nuxt mock:watch", 6 | "nuxt": "nuxt", 7 | "mock:build": "axios-mock-server --build", 8 | "mock:watch": "axios-mock-server --watch" 9 | }, 10 | "dependencies": { 11 | "nuxt": "^2.9.2", 12 | "@nuxtjs/axios": "^5.6.0" 13 | }, 14 | "devDependencies": { 15 | "axios-mock-server": "latest", 16 | "npm-run-all": "^4.1.5" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/createValues.ts: -------------------------------------------------------------------------------- 1 | export default (path: string, relativePath: string) => { 2 | const values: { [key: string]: string | number } = {} 3 | const dirList = path.split('/') 4 | const parsedRequestUrl = relativePath.split('/') 5 | 6 | parsedRequestUrl.forEach((dir, i) => { 7 | if (dirList[i].startsWith('_')) { 8 | const [valueName, type = 'number'] = dirList[i].slice(1).split('@') 9 | values[valueName] = isNaN(+dir) || type !== 'number' ? dir : +dir 10 | } 11 | }) 12 | 13 | return values 14 | } 15 | -------------------------------------------------------------------------------- /.versionrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "types": [ 3 | { "type": "build", "hidden": true }, 4 | { "type": "chore", "hidden": true }, 5 | { "type": "ci", "hidden": true }, 6 | { "type": "docs", "section": "Documentation" }, 7 | { "type": "feat", "section": "Features" }, 8 | { "type": "fix", "section": "Bug Fixes" }, 9 | { "type": "perf", "section": "Performance Improvements" }, 10 | { "type": "refactor", "section": "Refactors" }, 11 | { "type": "style", "hidden": true }, 12 | { "type": "test", "section": "Tests" } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Types of changes 2 | 3 | What kind of change does this PR introduce? (check at least one) 4 | 5 | 6 | 7 | - [ ] Breaking change 8 | - [ ] Bugfix 9 | - [ ] Feature 10 | - [ ] Code style update 11 | - [ ] Refactoring 12 | - [ ] Build related changes 13 | - [ ] CI related changes 14 | - [ ] Documentation content changes 15 | - [ ] Other... Please describe: 16 | 17 | ## Description 18 | 19 | 20 | 21 | Issue Number: N/A 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/lib/getConfig.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | 3 | export type Config = { 4 | input?: string | string[] 5 | target?: 'es6' | 'cjs' 6 | outputExt?: 'js' | 'ts' 7 | outputFilename?: string 8 | } 9 | 10 | export const mockFileRegExp = /\/(\$|@)/ 11 | 12 | export const defaultConfig = { 13 | input: fs.existsSync('mocks') || !fs.existsSync('apis') ? 'mocks' : 'apis', 14 | target: 'es6' as const, 15 | outputExt: 'js' as const 16 | } 17 | 18 | export default (rcFilePath = '.mockserverrc'): Config => 19 | fs.existsSync(rcFilePath) ? JSON.parse(fs.readFileSync(rcFilePath, 'utf8')) : {} 20 | -------------------------------------------------------------------------------- /examples/browser/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "browser", 3 | "private": true, 4 | "scripts": { 5 | "dev": "npm-run-all mock:build --parallel dev:server mock:watch", 6 | "dev:server": "webpack-dev-server", 7 | "mock:build": "axios-mock-server --build", 8 | "mock:watch": "axios-mock-server --watch" 9 | }, 10 | "dependencies": { 11 | "axios": "^0.19.0" 12 | }, 13 | "devDependencies": { 14 | "axios-mock-server": "latest", 15 | "npm-run-all": "^4.1.5", 16 | "webpack": "^4.39.3", 17 | "webpack-cli": "^3.3.8", 18 | "webpack-dev-server": "^3.8.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest a feature for axios-mock-server 4 | --- 5 | 6 | ## Description 7 | 8 | 9 | 10 | ## Describe the solution you'd like 11 | 12 | 13 | 14 | ## Describe alternatives you've considered 15 | 16 | 17 | 18 | ## Additional context 19 | 20 | 21 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "declaration": true, 5 | "declarationMap": true, 6 | "downlevelIteration": true, 7 | "esModuleInterop": true, 8 | "lib": ["dom", "dom.iterable", "esnext"], 9 | "module": "commonjs", 10 | "moduleResolution": "node", 11 | "outDir": "dist", 12 | "paths": { 13 | "~/*": ["./*"], 14 | "axios-mock-server": ["src"] 15 | }, 16 | "resolveJsonModule": true, 17 | "sourceMap": true, 18 | "strict": true, 19 | "target": "es5" 20 | }, 21 | "exclude": ["node_modules", "dist", "examples"] 22 | } 23 | -------------------------------------------------------------------------------- /examples/with-typescript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "with-typescript", 3 | "private": true, 4 | "scripts": { 5 | "dev": "npm-run-all mock:build --parallel watch mock:watch", 6 | "build": "axios-mock-server --build && tsc", 7 | "watch": "nodemon", 8 | "type-check": "tsc --noEmit", 9 | "mock:build": "axios-mock-server --build", 10 | "mock:watch": "axios-mock-server --watch" 11 | }, 12 | "dependencies": { 13 | "axios": "^0.19.0" 14 | }, 15 | "devDependencies": { 16 | "axios-mock-server": "latest", 17 | "nodemon": "^1.19.2", 18 | "npm-run-all": "^4.1.5", 19 | "typescript": "^3.6.3" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/createLogString.ts: -------------------------------------------------------------------------------- 1 | import { AxiosRequestConfig } from 'axios' 2 | import createRelativePath from './createRelativePath' 3 | 4 | export default (config: AxiosRequestConfig, status: number) => { 5 | const [dirPath, query] = (config.url || '').split('?') 6 | const relativePath = createRelativePath(dirPath, config.baseURL) 7 | const params = new URLSearchParams(query) 8 | Object.keys(config.params || {}).forEach(key => params.append(key, config.params[key])) 9 | const searchString = params.toString() 10 | 11 | return `[mock] ${config.method}: ${relativePath}${ 12 | searchString === '' ? '' : `?${searchString}` 13 | } => ${status}` 14 | } 15 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import 'url-search-params-polyfill' 2 | 3 | import { AxiosInstance } from 'axios' 4 | import { MockRoute, HttpMethod, MockResponse, MockMethods } from './types' 5 | import MockServer from './MockServer' 6 | import asyncResponse from './asyncResponse' 7 | 8 | export { asyncResponse, MockServer, MockRoute, HttpMethod, MockResponse, MockMethods } 9 | 10 | export default (route?: MockRoute, client?: AxiosInstance, baseURL = '') => 11 | new MockServer(route, client, baseURL) 12 | 13 | /* eslint-disable dot-notation */ 14 | module.exports = exports['default'] 15 | module.exports.default = exports['default'] 16 | module.exports.asyncResponse = asyncResponse 17 | -------------------------------------------------------------------------------- /src/makeResponse.ts: -------------------------------------------------------------------------------- 1 | import { AxiosRequestConfig, AxiosResponse } from 'axios' 2 | import { MockResponse } from './types' 3 | 4 | const copyData = (data?: any) => 5 | data && typeof data !== 'string' ? JSON.parse(JSON.stringify(data)) : data 6 | const arrayToObj = (mockRes: MockResponse) => 7 | Array.isArray(mockRes) ? { status: mockRes[0], data: mockRes[1], headers: mockRes[2] } : mockRes 8 | 9 | export default (mockRes: MockResponse, config: AxiosRequestConfig): AxiosResponse => { 10 | const { status, data, headers } = arrayToObj(mockRes) 11 | 12 | return { 13 | status, 14 | statusText: `${status}`, 15 | data: copyData(data), 16 | headers, 17 | config 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Report a bug in axios-mock-server 4 | --- 5 | 6 | ## Description 7 | 8 | 9 | 10 | ## Environment 11 | 12 | - **axios-mock-server version:** 13 | 14 | `vX.X.X` 15 | - **OS:** 16 | 17 | - [ ] Linux 18 | - [ ] Windows 19 | - [ ] macOS 20 | - **Node.js version:** 21 | 22 | `` 23 | - **npm version:** 24 | 25 | `` 26 | 27 | ## Additional context 28 | 29 | 30 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "npm" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | target-branch: "develop" 13 | versioning-strategy: "increase" 14 | commit-message: 15 | prefix: "fix" 16 | prefix-development: "chore" 17 | -------------------------------------------------------------------------------- /__tests__/lib/mocks/$mock.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | module.exports = (client) => require('axios-mock-server')([ 3 | { 4 | path: '/users/self', 5 | methods: require('./users/self') 6 | }, 7 | { 8 | path: '/users', 9 | methods: require('./users/index') 10 | }, 11 | { 12 | path: '/users/_userId', 13 | methods: require('./users/_userId') 14 | }, 15 | { 16 | path: '/search/_userName@string', 17 | methods: require('./search/_userName@string') 18 | }, 19 | { 20 | path: '/', 21 | methods: require('./index') 22 | }, 23 | { 24 | path: '/collections/entries.json', 25 | methods: require('./collections/entries.json') 26 | } 27 | ], client, 'https://example.com/api') 28 | -------------------------------------------------------------------------------- /__tests__/lib/mocks/$mock.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import { AxiosInstance } from 'axios' 3 | import mockServer from 'axios-mock-server' 4 | import mock0 from './users/self' 5 | import mock1 from './users/index' 6 | import mock2 from './users/_userId' 7 | import mock3 from './search/_userName@string' 8 | import mock4 from './index' 9 | import mock5 from './collections/entries.json' 10 | 11 | export default (client?: AxiosInstance) => mockServer([ 12 | { 13 | path: '/users/self', 14 | methods: mock0 15 | }, 16 | { 17 | path: '/users', 18 | methods: mock1 19 | }, 20 | { 21 | path: '/users/_userId', 22 | methods: mock2 23 | }, 24 | { 25 | path: '/search/_userName@string', 26 | methods: mock3 27 | }, 28 | { 29 | path: '/', 30 | methods: mock4 31 | }, 32 | { 33 | path: '/collections/entries.json', 34 | methods: mock5 35 | } 36 | ], client, 'https://example.com/api') 37 | -------------------------------------------------------------------------------- /src/lib/cli.ts: -------------------------------------------------------------------------------- 1 | import minimist from 'minimist' 2 | import getConfig from './getConfig' 3 | import getInputs from './getInputs' 4 | import build from './buildRouteFile' 5 | import write from './writeRouteFile' 6 | import watch from './watchInputDir' 7 | 8 | export const run = (args: string[]) => { 9 | const argv = minimist(args, { 10 | string: ['version', 'config', 'watch', 'baseurl'], 11 | alias: { v: 'version', c: 'config', w: 'watch', u: 'baseurl' } 12 | }) 13 | const config = getConfig(argv.config) 14 | 15 | // eslint-disable-next-line no-unused-expressions 16 | argv.version !== undefined 17 | ? console.log(`v${require('../../package.json').version}`) 18 | : argv.watch !== undefined 19 | ? getInputs(config.input).forEach(input => { 20 | write(build(input, config, argv.baseurl)) 21 | watch(input, () => write(build(input, config, argv.baseurl))) 22 | }) 23 | : getInputs(config.input) 24 | .map(input => build(input, config, argv.baseurl)) 25 | .forEach(write) 26 | } 27 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | import { AxiosRequestConfig } from 'axios' 2 | import createValues from './createValues' 3 | import compositeParams from './compositeParams' 4 | 5 | export const httpMethods = ['get', 'post', 'put', 'delete', 'head', 'patch'] as const 6 | 7 | export type HttpMethod = typeof httpMethods[number] 8 | 9 | export type MockResponse = 10 | | [number, any?, { [key: string]: any }?] 11 | | { status: number; data?: any; headers?: { [key: string]: any } } 12 | 13 | export type MockMethods = { 14 | [T in HttpMethod]?: ({ 15 | config, 16 | values, 17 | params, 18 | data 19 | }: { 20 | config: AxiosRequestConfig 21 | values: ReturnType 22 | params: ReturnType 23 | data: any 24 | }) => MockResponse | Promise 25 | } 26 | 27 | type Handler = [RegExp, string, MockMethods[HttpMethod]] 28 | export type HandlersSet = { [key in HttpMethod]?: Handler[] } 29 | 30 | export type MockRoute = { 31 | path: string 32 | methods: MockMethods 33 | }[] 34 | -------------------------------------------------------------------------------- /src/findAndCallHandler.ts: -------------------------------------------------------------------------------- 1 | import { AxiosRequestConfig } from 'axios' 2 | import { HandlersSet } from './types' 3 | import findHandler from './findHandler' 4 | import createValues from './createValues' 5 | import untransformData from './untransformData' 6 | import compositeParams from './compositeParams' 7 | import createRelativePath from './createRelativePath' 8 | 9 | export default (config: AxiosRequestConfig, handlersSet: HandlersSet) => { 10 | // eslint-disable-next-line @typescript-eslint/no-non-null-assertion 11 | const [dirPath, query] = config.url!.split('?') 12 | const relativePath = createRelativePath(dirPath, config.baseURL) 13 | const handler = findHandler(config.method, relativePath, handlersSet) 14 | 15 | return ( 16 | handler && 17 | // eslint-disable-next-line @typescript-eslint/no-non-null-assertion 18 | handler[2]!({ 19 | config, 20 | values: createValues(handler[1], relativePath), 21 | params: compositeParams(query, config.params), 22 | data: untransformData(config.data, config.headers) 23 | }) 24 | ) 25 | } 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Solufa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/lib/buildRouteFile.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import path from 'path' 3 | import { Config, defaultConfig, mockFileRegExp } from './getConfig' 4 | import { listFiles } from './listFiles' 5 | import createRouteString from './createRouteString' 6 | 7 | const getTarget = (filePath?: string) => 8 | !filePath 9 | ? defaultConfig.target 10 | : /(\n|^)export default/.test(fs.readFileSync(filePath, 'utf8')) 11 | ? 'es6' 12 | : 'cjs' 13 | 14 | const findExportingFile = (filePaths: string[]) => 15 | filePaths.find(filePath => /export/.test(fs.readFileSync(filePath, 'utf8'))) 16 | 17 | const getMockFilePaths = (input: string, filename = '') => 18 | listFiles(input) 19 | .filter( 20 | filePath => 21 | filePath !== filename && 22 | !mockFileRegExp.test(filePath) && 23 | /^\.(js|ts)$/.test(path.extname(filePath)) && 24 | /(\n|^)(export default|module.exports)/.test(fs.readFileSync(filePath, 'utf8')) 25 | ) 26 | .sort() 27 | .reverse() 28 | 29 | export default (input: string, config: Config, baseURL = '') => { 30 | const mockFilePaths = getMockFilePaths(input, config.outputFilename) 31 | const ext = 32 | config.outputExt || 33 | (config.outputFilename ?? '').split('.').pop() || 34 | (mockFilePaths[0] ? path.extname(mockFilePaths[0]).slice(1) : defaultConfig.outputExt) 35 | const text = createRouteString( 36 | input, 37 | config.target || getTarget(findExportingFile(mockFilePaths)), 38 | ext === 'ts', 39 | mockFilePaths, 40 | baseURL 41 | ) 42 | 43 | return { text, filePath: path.posix.join(input, config.outputFilename ?? `$mock.${ext}`) } 44 | } 45 | -------------------------------------------------------------------------------- /src/lib/createRouteString.ts: -------------------------------------------------------------------------------- 1 | const moduleName = "'axios-mock-server'" 2 | const eslintComment = '/* eslint-disable */' 3 | const createImportPath = (filePath: string, inputDir: string) => 4 | filePath 5 | .replace(new RegExp(`^(.\\/)?${inputDir.replace(/^.\//, '').replace(/\/$/, '')}`), '') 6 | .replace(/\.(ts|js)$/, '') 7 | 8 | const createCondition = (filePath: string, inputDir: string, methods: string) => ` 9 | { 10 | path: '${createImportPath(filePath, inputDir).replace(/(\/index)$/, '') || '/'}', 11 | methods: ${methods} 12 | }` 13 | 14 | export default ( 15 | inputDir: string, 16 | target: 'es6' | 'cjs', 17 | isTS: boolean, 18 | pathList: string[], 19 | baseURL = '' 20 | ) => 21 | target === 'es6' 22 | ? `${eslintComment} 23 | ${ 24 | isTS 25 | ? `import { AxiosInstance } from 'axios' 26 | ` 27 | : '' 28 | }import mockServer from ${moduleName} 29 | ${pathList 30 | .map( 31 | (filePath, i) => `import mock${i} from '.${createImportPath(filePath, inputDir)}' 32 | ` 33 | ) 34 | .join('')} 35 | export default (client${ 36 | isTS ? '?: AxiosInstance' : '' 37 | }) => mockServer([${pathList 38 | .map((filePath, i) => createCondition(filePath, inputDir, `mock${i}`)) 39 | .join(',')} 40 | ], client, '${baseURL}') 41 | ` 42 | : `${eslintComment} 43 | ${ 44 | isTS 45 | ? `import { AxiosInstance } = require('axios') 46 | ` 47 | : '' 48 | }module.exports = (client${ 49 | isTS ? '?: AxiosInstance' : '' 50 | }) => require(${moduleName})([${pathList 51 | .map(filePath => 52 | createCondition(filePath, inputDir, `require('.${createImportPath(filePath, inputDir)}')`) 53 | ) 54 | .join(',')} 55 | ], client, '${baseURL}') 56 | ` 57 | -------------------------------------------------------------------------------- /__tests__/lib/index.spec.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import { version } from '~/package.json' 3 | import { run } from '~/src/lib/cli' 4 | import build from '~/src/lib/buildRouteFile' 5 | 6 | describe('cli', () => { 7 | test('version command', () => { 8 | const spyLog = jest.spyOn(console, 'log') 9 | const args = ['--version'] 10 | 11 | run(args) 12 | expect(console.log).toHaveBeenCalledWith(`v${version}`) 13 | 14 | spyLog.mockRestore() 15 | }) 16 | 17 | test('snapshot', () => { 18 | const configs = [ 19 | { 20 | input: '__tests__/lib/mocks', 21 | resultDirPath: '__tests__/lib/mocks', 22 | target: 'es6' as const, 23 | outputExt: 'ts' as const 24 | }, 25 | { 26 | input: '__tests__/lib/mocks', 27 | resultDirPath: '__tests__/lib/mocks', 28 | target: 'cjs' as const, 29 | outputExt: 'js' as const 30 | }, 31 | { 32 | input: './__tests__/lib/mocks', 33 | resultDirPath: '__tests__/lib/mocks', 34 | target: 'es6' as const, 35 | outputExt: 'ts' as const 36 | }, 37 | { 38 | input: './__tests__/lib/mocks', 39 | resultDirPath: '__tests__/lib/mocks', 40 | target: 'cjs' as const, 41 | outputExt: 'js' as const 42 | }, 43 | { 44 | input: '__tests__/lib/mocks/', 45 | resultDirPath: '__tests__/lib/mocks', 46 | target: 'es6' as const, 47 | outputExt: 'ts' as const 48 | }, 49 | { 50 | input: '__tests__/lib/mocks/', 51 | resultDirPath: '__tests__/lib/mocks', 52 | target: 'cjs' as const, 53 | outputExt: 'js' as const 54 | } 55 | ] 56 | 57 | configs.forEach(config => { 58 | const resultFilePath = `${config.resultDirPath}/$mock.${config.outputExt}` 59 | const result = fs.readFileSync(resultFilePath, 'utf8') 60 | const { text, filePath } = build(config.input, config, 'https://example.com/api') 61 | 62 | expect(text).toBe(result.replace(/\r/g, '')) 63 | expect(filePath).toBe(resultFilePath) 64 | }) 65 | }) 66 | }) 67 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Node.js 2 | 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | lerna-debug.log* 10 | 11 | # Diagnostic reports (https://nodejs.org/api/report.html) 12 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 13 | 14 | # Runtime data 15 | pids 16 | *.pid 17 | *.seed 18 | *.pid.lock 19 | 20 | # Directory for instrumented libs generated by jscoverage/JSCover 21 | lib-cov 22 | 23 | # Coverage directory used by tools like istanbul 24 | coverage 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # TypeScript v1 declaration files 46 | typings/ 47 | 48 | # Optional npm cache directory 49 | .npm 50 | 51 | # Optional eslint cache 52 | .eslintcache 53 | 54 | # Optional stylelint cache 55 | .stylelintcache 56 | 57 | # Optional REPL history 58 | .node_repl_history 59 | 60 | # Output of 'npm pack' 61 | *.tgz 62 | 63 | # Yarn Integrity file 64 | .yarn-integrity 65 | 66 | # dotenv environment variables file 67 | .env 68 | .env.test 69 | 70 | # parcel-bundler cache (https://parceljs.org/) 71 | .cache 72 | 73 | # next.js build output 74 | .next 75 | 76 | # nuxt.js build output 77 | .nuxt 78 | 79 | # Nuxt generate 80 | dist 81 | 82 | # vuepress build output 83 | .vuepress/dist 84 | 85 | # Serverless directories 86 | .serverless/ 87 | 88 | # FuseBox cache 89 | .fusebox/ 90 | 91 | # DynamoDB Local files 92 | .dynamodb/ 93 | 94 | 95 | # IDE 96 | .idea 97 | 98 | # Service worker 99 | sw.* 100 | 101 | 102 | ### Visual Studio Code 103 | 104 | .vscode/* 105 | !.vscode/settings.json 106 | !.vscode/tasks.json 107 | !.vscode/launch.json 108 | !.vscode/extensions.json 109 | 110 | 111 | ### Miscellaneous 112 | 113 | # examples directory 114 | examples/**/$mock.* 115 | examples/**/package-lock.json 116 | -------------------------------------------------------------------------------- /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | name: Node.js CI 2 | 3 | on: push 4 | 5 | jobs: 6 | test: 7 | name: "Test on Node:${{ matrix.node-version }} OS:${{ matrix.os }}" 8 | runs-on: ${{ matrix.os }} 9 | strategy: 10 | matrix: 11 | node-version: [12, 14] 12 | os: [windows-latest, ubuntu-latest] 13 | steps: 14 | - uses: actions/checkout@v2 15 | - name: setup Node.js ${{ matrix.node-version }} 16 | uses: actions/setup-node@v1 17 | with: 18 | node-version: ${{ matrix.node-version }} 19 | - name: Get yarn cache directory path 20 | id: yarn-cache-dir-path 21 | run: echo "::set-output name=dir::$(yarn cache dir)" 22 | - uses: actions/cache@v2 23 | id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) 24 | with: 25 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 26 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 27 | restore-keys: | 28 | ${{ runner.os }}-yarn- 29 | - run: yarn --frozen-lockfile 30 | - run: yarn lint 31 | if: matrix.os != 'windows-latest' 32 | - run: yarn typecheck 33 | - run: yarn test --coverage 34 | - run: npx codecov 35 | if: github.ref == 'refs/heads/master' && matrix.os == 'ubuntu-latest' && matrix.node-version == 14 36 | env: 37 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 38 | 39 | release: 40 | runs-on: ubuntu-latest 41 | needs: test 42 | if: contains(github.ref, 'tags/v') 43 | steps: 44 | - uses: actions/checkout@v2 45 | - name: Use Node.js 46 | uses: actions/setup-node@v1 47 | with: 48 | node-version: "12.x" 49 | registry-url: "https://registry.npmjs.org" 50 | - name: Get yarn cache directory path 51 | id: yarn-cache-dir-path 52 | run: echo "::set-output name=dir::$(yarn cache dir)" 53 | - uses: actions/cache@v2 54 | id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) 55 | with: 56 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 57 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 58 | restore-keys: | 59 | ${{ runner.os }}-yarn- 60 | - run: yarn --frozen-lockfile 61 | - run: yarn build 62 | - run: npm publish 63 | env: 64 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 65 | -------------------------------------------------------------------------------- /src/MockServer.ts: -------------------------------------------------------------------------------- 1 | import axios, { AxiosInstance, AxiosAdapter } from 'axios' 2 | import settle from 'axios/lib/core/settle' 3 | import { HandlersSet, MockRoute, httpMethods } from './types' 4 | import createLogString from './createLogString' 5 | import makeResponse from './makeResponse' 6 | import findAndCallHandler from './findAndCallHandler' 7 | 8 | export const createPathRegExp = (path: string) => 9 | new RegExp(`^${path.replace(/\/_[^/]+/g, '/[^/]+')}$`) 10 | 11 | export default class { 12 | private handlersSet: HandlersSet = {} 13 | private delayTime = 0 14 | private needsLog = false 15 | private client?: AxiosInstance 16 | private originalAdapter?: AxiosAdapter 17 | private baseURL = '' 18 | 19 | constructor(route?: MockRoute, client?: AxiosInstance, baseURL = '') { 20 | if (route) 21 | this.setBaseURL(baseURL) 22 | .setClient(client || axios) 23 | .setRoute(route) 24 | } 25 | 26 | public setClient(client: AxiosInstance) { 27 | this.client = client 28 | this.originalAdapter = client.defaults.adapter 29 | 30 | client.defaults.adapter = config => 31 | // eslint-disable-next-line no-async-promise-executor 32 | new Promise(async (resolve, reject) => { 33 | const customConfig = { 34 | ...config, 35 | baseURL: config.baseURL || this.baseURL 36 | } 37 | 38 | try { 39 | const result = findAndCallHandler(customConfig, this.handlersSet) 40 | 41 | if (!result && this.originalAdapter) { 42 | this.originalAdapter(customConfig).then(resolve, reject) 43 | return 44 | } 45 | 46 | const res = result 47 | ? makeResponse(result instanceof Promise ? await result : result, customConfig) 48 | : { status: 404, config: customConfig } 49 | 50 | if (this.needsLog) console.log(createLogString(customConfig, res.status)) 51 | 52 | setTimeout(() => settle(resolve, reject, res), this.delayTime) 53 | } catch (e) { 54 | reject(e) 55 | } 56 | }) 57 | 58 | return this 59 | } 60 | 61 | public setRoute(route: MockRoute) { 62 | route.forEach(r => { 63 | const pathRegExp = createPathRegExp(r.path) 64 | 65 | httpMethods.forEach(method => { 66 | if (r.methods[method]) { 67 | this.handlersSet[method] = [ 68 | ...(this.handlersSet[method] || []), 69 | [pathRegExp, r.path, r.methods[method]] 70 | ] 71 | } 72 | }) 73 | }) 74 | 75 | return this 76 | } 77 | 78 | public setDelayTime(delayTime: number) { 79 | this.delayTime = delayTime 80 | return this 81 | } 82 | 83 | public setBaseURL(baseURL: string) { 84 | this.baseURL = baseURL 85 | return this 86 | } 87 | 88 | public reset() { 89 | this.setDelayTime(0).disableLog() 90 | this.handlersSet = {} 91 | return this 92 | } 93 | 94 | public restore() { 95 | if (!this.client) return 96 | 97 | this.reset() 98 | delete this.client.defaults.adapter 99 | 100 | if (this.originalAdapter) { 101 | this.client.defaults.adapter = this.originalAdapter 102 | delete this.originalAdapter 103 | } 104 | 105 | delete this.client 106 | return this 107 | } 108 | 109 | public enableLog() { 110 | this.needsLog = true 111 | return this 112 | } 113 | 114 | public disableLog() { 115 | this.needsLog = false 116 | return this 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "axios-mock-server", 3 | "version": "0.19.1", 4 | "description": "RESTful mock server using axios", 5 | "author": "Solufa ", 6 | "license": "MIT", 7 | "main": "dist/index.js", 8 | "bin": "bin/index.js", 9 | "scripts": { 10 | "dev": "npm run build && node bin/index.js -c devConfigs/.js.rc -b -u https://example.com/api && node bin/index.js -c devConfigs/.ts.rc -b -u https://example.com/api", 11 | "build": "node -e \"require('fs').rmdirSync('dist', { recursive: true })\" && tsc -p tsconfig.build.json", 12 | "release": "standard-version --skip.tag", 13 | "release:major": "npm run release -- --release-as major", 14 | "release:minor": "npm run release -- --release-as minor", 15 | "release:patch": "npm run release -- --release-as patch", 16 | "lint": "eslint --ext .js,.ts --ignore-path .gitignore .", 17 | "lint:fix": "npm run lint -- --fix", 18 | "typecheck": "tsc --noEmit", 19 | "test": "jest" 20 | }, 21 | "homepage": "https://github.com/solufa/axios-mock-server#readme", 22 | "repository": { 23 | "type": "git", 24 | "url": "git+https://github.com/solufa/axios-mock-server.git" 25 | }, 26 | "bugs": { 27 | "url": "https://github.com/solufa/axios-mock-server/issues" 28 | }, 29 | "files": [ 30 | "dist" 31 | ], 32 | "keywords": [ 33 | "axios", 34 | "test", 35 | "mock" 36 | ], 37 | "eslintConfig": { 38 | "env": { 39 | "es6": true, 40 | "node": true, 41 | "browser": true 42 | }, 43 | "extends": [ 44 | "standard", 45 | "plugin:@typescript-eslint/recommended", 46 | "plugin:jest/recommended", 47 | "plugin:prettier/recommended", 48 | "prettier/@typescript-eslint", 49 | "prettier/standard" 50 | ], 51 | "parserOptions": { 52 | "ecmaVersion": 2018, 53 | "sourceType": "module" 54 | }, 55 | "root": true, 56 | "rules": { 57 | "@typescript-eslint/explicit-function-return-type": "off", 58 | "@typescript-eslint/ban-ts-comment": "off", 59 | "@typescript-eslint/explicit-module-boundary-types": "off", 60 | "@typescript-eslint/no-var-requires": "off", 61 | "@typescript-eslint/ban-types": "off", 62 | "@typescript-eslint/camelcase": "off", 63 | "@typescript-eslint/no-explicit-any": "off" 64 | } 65 | }, 66 | "prettier": { 67 | "printWidth": 100, 68 | "semi": false, 69 | "arrowParens": "avoid", 70 | "singleQuote": true, 71 | "trailingComma": "none", 72 | "overrides": [ 73 | { 74 | "files": [ 75 | "*.md", 76 | "*.yml" 77 | ], 78 | "options": { 79 | "singleQuote": false 80 | } 81 | } 82 | ] 83 | }, 84 | "devDependencies": { 85 | "@types/jest": "^26.0.20", 86 | "@types/minimist": "^1.2.1", 87 | "@typescript-eslint/eslint-plugin": "^4.15.0", 88 | "@typescript-eslint/parser": "^4.15.0", 89 | "axios": "^0.21.1", 90 | "eslint": "^7.20.0", 91 | "eslint-config-prettier": "^7.2.0", 92 | "eslint-config-standard": "^16.0.2", 93 | "eslint-plugin-import": "^2.22.1", 94 | "eslint-plugin-jest": "^24.1.3", 95 | "eslint-plugin-node": "^11.1.0", 96 | "eslint-plugin-prettier": "^3.3.1", 97 | "eslint-plugin-promise": "^4.3.1", 98 | "eslint-plugin-standard": "^5.0.0", 99 | "jest": "^26.6.3", 100 | "prettier": "^2.2.1", 101 | "standard-version": "^9.1.0", 102 | "ts-jest": "^26.5.1", 103 | "typescript": "^4.1.5" 104 | }, 105 | "dependencies": { 106 | "chokidar": "^3.5.1", 107 | "minimist": "^1.2.5", 108 | "url-search-params-polyfill": "^8.1.0" 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /__tests__/units.spec.ts: -------------------------------------------------------------------------------- 1 | import { AxiosRequestConfig } from 'axios' 2 | import { HandlersSet, HttpMethod } from '~/src/types' 3 | import { asyncResponse } from '~/src' 4 | import createValues from '~/src/createValues' 5 | import findHandler from '~/src/findHandler' 6 | import { createPathRegExp } from '~/src/MockServer' 7 | import createRelativePath from '~/src/createRelativePath' 8 | import createLogString from '~/src/createLogString' 9 | import untransformData from '~/src/untransformData' 10 | 11 | describe('unit tests', () => { 12 | test('createValues', () => { 13 | const list: { 14 | conditions: [string, string] 15 | values: { [key: string]: string | number } 16 | }[] = [ 17 | { 18 | conditions: ['/aa/_bb/cc/_dd', '/aa/hoge/cc/123'], 19 | values: { bb: 'hoge', dd: 123 } 20 | }, 21 | { 22 | conditions: ['/aa/_bb/cc/_dd@number', '/aa/hoge/cc/123'], 23 | values: { bb: 'hoge', dd: 123 } 24 | }, 25 | { 26 | conditions: ['/aa/_bb/cc/_dd@string', '/aa/hoge/cc/123'], 27 | values: { bb: 'hoge', dd: '123' } 28 | } 29 | ] 30 | 31 | list.forEach(({ conditions, values }) => expect(createValues(...conditions)).toEqual(values)) 32 | }) 33 | 34 | test('findHandler', () => { 35 | const list = [ 36 | { 37 | method: 'get', 38 | path: '/aa/hoge/cc/123', 39 | handlersSet: { get: [[createPathRegExp('/aa/_bb/cc/_dd'), '/aa/_bb/cc/_dd', () => [200]]] }, 40 | resultIndex: 0 41 | }, 42 | { 43 | method: 'get', 44 | path: '/zz/aa/hoge/cc/123', 45 | handlersSet: { get: [[createPathRegExp('/aa/_bb/cc/_dd'), '/aa/_bb/cc/_dd', () => [200]]] }, 46 | resultIndex: undefined 47 | }, 48 | { 49 | method: 'post', 50 | path: '/aa/hoge/cc/123', 51 | handlersSet: { get: [[createPathRegExp('/aa/_bb/cc/_dd'), '/aa/_bb/cc/_dd', () => [200]]] }, 52 | resultIndex: undefined 53 | }, 54 | { 55 | method: 'get', 56 | path: '/aa/hoge/cc', 57 | handlersSet: { get: [[createPathRegExp('/aa/_bb/cc/_dd'), '/aa/_bb/cc/_dd', () => [200]]] }, 58 | resultIndex: undefined 59 | }, 60 | { 61 | method: 'post', 62 | path: '/aa/hoge/cc', 63 | handlersSet: { 64 | post: [ 65 | [createPathRegExp('/aa/_bb/cc/_dd'), '/aa/_bb/cc/_dd', () => [200]], 66 | [createPathRegExp('/aa/_bb/cc'), '/aa/_bb/cc', () => [200]] 67 | ] 68 | }, 69 | resultIndex: 1 70 | }, 71 | { 72 | method: undefined, 73 | path: '/aa', 74 | handlersSet: { get: [[createPathRegExp('/aa'), '/aa', () => [200]]] }, 75 | resultIndex: undefined 76 | } 77 | ] 78 | 79 | list.forEach(({ method, path, handlersSet, resultIndex }) => 80 | expect(findHandler(method, path, handlersSet as HandlersSet)).toBe( 81 | resultIndex === undefined 82 | ? undefined 83 | : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion 84 | (handlersSet as HandlersSet)[method as HttpMethod]![resultIndex] 85 | ) 86 | ) 87 | }) 88 | 89 | test('asyncResponse', async () => { 90 | const result = [200, { test: 'aaa' }, { 'cache-control': 'max-age=0' }] as const 91 | const res = await asyncResponse(result[0], (async () => result[1])(), result[2]) 92 | expect(res).toEqual(result) 93 | }) 94 | 95 | test('createRelativePath', () => { 96 | const paths = [ 97 | { url: '//apple.com/aa/bb', baseURL: 'https://google.com/', result: '/aa/bb' }, 98 | { url: '/aa/bb', baseURL: undefined, result: '/aa/bb' }, 99 | { url: '/cc/dd/', baseURL: '/aa/bb', result: '/cc/dd' }, 100 | { url: undefined, baseURL: 'https://google.com/abc/', result: '/' }, 101 | { url: undefined, baseURL: undefined, result: '/' } 102 | ] 103 | 104 | paths.forEach(path => expect(createRelativePath(path.url, path.baseURL)).toBe(path.result)) 105 | }) 106 | 107 | test('createLogString', () => { 108 | const configs = [ 109 | { 110 | config: { 111 | method: 'get', 112 | url: '/bb/?cc=123', 113 | baseURL: '//google.com/aa' 114 | }, 115 | status: 200, 116 | result: '[mock] get: /bb?cc=123 => 200' 117 | }, 118 | { 119 | config: { 120 | method: 'post', 121 | url: '/bb/?cc=123', 122 | params: { dd: 'abc' } 123 | }, 124 | status: 201, 125 | result: '[mock] post: /bb?cc=123&dd=abc => 201' 126 | }, 127 | { 128 | config: { 129 | method: 'put', 130 | baseURL: '//google.com/aa', 131 | params: { dd: 'abc' } 132 | }, 133 | status: 204, 134 | result: '[mock] put: /?dd=abc => 204' 135 | }, 136 | { 137 | config: { 138 | method: 'delete', 139 | url: '?aa=123', 140 | params: { bb: 'abc' } 141 | }, 142 | status: 204, 143 | result: '[mock] delete: /?aa=123&bb=abc => 204' 144 | } 145 | ] 146 | 147 | configs.forEach(c => 148 | expect(createLogString(c.config as AxiosRequestConfig, c.status)).toBe(c.result) 149 | ) 150 | }) 151 | 152 | test('untransformData', () => { 153 | expect(untransformData('{"aa": 1}', { 'Content-Type': 'application/json' })).toEqual({ aa: 1 }) 154 | expect(untransformData(undefined, {})).toBe(undefined) 155 | 156 | const fakeImage = {} 157 | expect(untransformData(fakeImage, { 'Content-Type': 'image/jpeg' })).toBe(fakeImage) 158 | 159 | const params: URLSearchParams = untransformData('foo=1&bar=2', { 160 | 'Content-Type': 'application/x-www-form-urlencoded' 161 | }) 162 | expect(params.get('foo')).toBe('1') 163 | expect(params.get('bar')).toBe('2') 164 | }) 165 | }) 166 | -------------------------------------------------------------------------------- /__tests__/index.spec.ts: -------------------------------------------------------------------------------- 1 | import axios, { AxiosInstance } from 'axios' 2 | import mockServer, { MockRoute, asyncResponse, MockResponse } from '~/src' 3 | 4 | describe('initialize', () => { 5 | const mock = mockServer() 6 | let client: AxiosInstance 7 | 8 | beforeEach(() => { 9 | client = axios.create({ baseURL: 'https://google.com/aa' }) 10 | mock.setClient(client) 11 | }) 12 | 13 | afterEach(() => mock.reset()) 14 | 15 | test('enabled mock', async () => { 16 | const route: MockRoute = [] 17 | 18 | mock.setRoute(route) 19 | await expect(client.get('/')).rejects.toHaveProperty('response.status', 404) 20 | }) 21 | 22 | test('default axios', async () => { 23 | const testPath = '/test' 24 | const defaultValue = { name: 'test' } 25 | const route: MockRoute = [ 26 | { 27 | path: testPath, 28 | methods: { get: () => [200, defaultValue] } 29 | } 30 | ] 31 | 32 | const mock = mockServer(route) 33 | 34 | const { data } = await axios.get(testPath) 35 | 36 | expect(data).toEqual(defaultValue) 37 | expect(data).not.toBe(defaultValue) 38 | 39 | mock.restore() 40 | }) 41 | 42 | test('get object', async () => { 43 | const testPath = '/test' 44 | const defaultValue = [{ name: 'test1' }, { name: 'test2' }] 45 | const route: MockRoute = [ 46 | { 47 | path: testPath, 48 | methods: { get: () => [200, defaultValue] } 49 | } 50 | ] 51 | 52 | mock.setRoute(route) 53 | const { data } = await client.get(testPath) 54 | 55 | expect(data).toEqual(defaultValue) 56 | expect(data).not.toBe(defaultValue) 57 | }) 58 | 59 | test('get without baseURL', async () => { 60 | const axiosInstance = axios.create() 61 | const testPath = '/test' 62 | const defaultValue = { name: 'test' } 63 | const route: MockRoute = [ 64 | { 65 | path: testPath, 66 | methods: { get: () => [200, defaultValue] } 67 | } 68 | ] 69 | 70 | mockServer(route, axiosInstance) 71 | const { data } = await axiosInstance.get(testPath) 72 | 73 | expect(data).toEqual(defaultValue) 74 | }) 75 | 76 | test('get path through', async () => { 77 | const axiosInstance = axios.create({ baseURL: 'https://google.com/' }) 78 | const testPath = '/test' 79 | const defaultValue = [{ name: 'test1' }, { name: 'test2' }] 80 | const route: MockRoute = [ 81 | { 82 | path: testPath, 83 | methods: { get: () => [200, defaultValue] } 84 | } 85 | ] 86 | 87 | mockServer(route, axiosInstance) 88 | 89 | const { status } = await axiosInstance.get('/') 90 | expect(status).toBe(200) 91 | 92 | const { data } = await axiosInstance.get(testPath) 93 | expect(data).toEqual(defaultValue) 94 | }) 95 | 96 | test('get with query and params', async () => { 97 | const response = { name: 'mario', height: 155, color: 'red' } 98 | const testPath = '/test' 99 | const route: MockRoute = [ 100 | { 101 | path: testPath, 102 | methods: { get: ({ params }) => [200, params] } 103 | } 104 | ] 105 | 106 | mock.setRoute(route) 107 | const { data } = await client.get( 108 | `${testPath}/?height=${response.height}&color=${response.color}`, 109 | { 110 | params: { name: response.name } 111 | } 112 | ) 113 | 114 | expect(data).toEqual(response) 115 | }) 116 | 117 | test('404 request', async () => { 118 | const testPath = '/test' 119 | const route: MockRoute = [{ path: testPath, methods: {} }] 120 | 121 | mock.setRoute(route) 122 | await expect(client.get(testPath)).rejects.toHaveProperty('response.status', 404) 123 | }) 124 | 125 | test('get with params', async () => { 126 | const testPath = '/test' 127 | const name = 'mario' 128 | const route: MockRoute = [ 129 | { 130 | path: testPath, 131 | methods: { get: ({ params }) => [200, params.name] } 132 | } 133 | ] 134 | 135 | mock.setRoute(route) 136 | const { data } = await client.get(testPath, { params: { name } }) 137 | 138 | expect(data).toEqual(name) 139 | }) 140 | 141 | test('get with values', async () => { 142 | const testRegPath = '/test/_name/hoge.json' 143 | const name = 'mario' 144 | const testPath = `/test/${name}/hoge.json` 145 | const route: MockRoute = [ 146 | { 147 | path: testRegPath, 148 | methods: { get: ({ values }) => [200, { name: values.name }] } 149 | } 150 | ] 151 | 152 | mock.setRoute(route) 153 | const { data } = await client.get(testPath) 154 | 155 | expect(data.name).toEqual(name) 156 | }) 157 | 158 | test('get with typed values', async () => { 159 | const testRegPath = '/test/_name@string/hoge.json' 160 | const name = '12345' 161 | const testPath = `/test/${name}/hoge.json` 162 | const route: MockRoute = [ 163 | { 164 | path: testRegPath, 165 | methods: { get: ({ values }) => [200, { name: values.name }] } 166 | } 167 | ] 168 | 169 | mock.setRoute(route) 170 | const { data } = await client.get(testPath) 171 | 172 | expect(data.name).toEqual(name) 173 | }) 174 | 175 | test('post with data', async () => { 176 | const testPath = '/test' 177 | const name = 'mario' 178 | const route: MockRoute = [ 179 | { 180 | path: testPath, 181 | methods: { post: ({ data: { name } }) => [201, name] } 182 | } 183 | ] 184 | 185 | mock.setRoute(route) 186 | const { data } = await client.post(testPath, { name }) 187 | 188 | expect(data).toEqual(name) 189 | }) 190 | 191 | test('post with data by x-www-form-urlencoded', async () => { 192 | const testPath = '/test' 193 | const name = 'mario' 194 | const params = new URLSearchParams() 195 | params.append('name', name) 196 | 197 | const route: MockRoute = [ 198 | { 199 | path: testPath, 200 | methods: { post: ({ data }) => [201, data.get('name')] } 201 | } 202 | ] 203 | 204 | mock.setRoute(route) 205 | const { data } = await client.post(testPath, params) 206 | 207 | expect(data).toEqual(name) 208 | }) 209 | 210 | test('put with data', async () => { 211 | const testPath = '/test' 212 | const name = 'mario' 213 | const route: MockRoute = [ 214 | { 215 | path: testPath, 216 | methods: { put: ({ data: { name } }) => [200, name] } 217 | } 218 | ] 219 | 220 | mock.setRoute(route) 221 | const { data } = await client.put(testPath, { name }) 222 | 223 | expect(data).toEqual(name) 224 | }) 225 | 226 | test('delete with data', async () => { 227 | const testPath = '/test' 228 | const name = 'mario' 229 | const route: MockRoute = [ 230 | { 231 | path: testPath, 232 | methods: { delete: ({ data: { name } }) => [200, name] } 233 | } 234 | ] 235 | 236 | mock.setRoute(route) 237 | const { data } = await client.delete(testPath, { data: { name } }) 238 | 239 | expect(data).toEqual(name) 240 | }) 241 | 242 | test('response 401 error', async () => { 243 | const testPath = '/test' 244 | const status = 401 245 | const route: MockRoute = [{ path: testPath, methods: { get: () => [status] } }] 246 | 247 | mock.setRoute(route) 248 | await expect(client.get(testPath)).rejects.toHaveProperty('response.status', status) 249 | }) 250 | 251 | test('response 500 error', async () => { 252 | const testPath = '/test' 253 | const status = 500 254 | const route: MockRoute = [{ path: testPath, methods: { get: () => [status] } }] 255 | 256 | mock.setRoute(route) 257 | await expect(client.get(testPath)).rejects.toHaveProperty('response.status', status) 258 | }) 259 | 260 | test('set delayTime', async () => { 261 | const delayTime = 500 262 | const testPath = '/test' 263 | const route: MockRoute = [{ path: testPath, methods: { get: () => [204] } }] 264 | 265 | mock.setRoute(route).setDelayTime(delayTime) 266 | const startTime = Date.now() 267 | 268 | await client.get(testPath) 269 | 270 | const elapsedTime = Date.now() - startTime 271 | expect(elapsedTime).toBeGreaterThanOrEqual(delayTime - 1) 272 | expect(elapsedTime).toBeLessThan(delayTime + 20) 273 | }) 274 | 275 | test('async methods', async () => { 276 | const testPath = '/test' 277 | const name = 'mario' 278 | const errorStatus = 500 279 | const errorMessage = 'error test' 280 | const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)) 281 | const route: MockRoute = [ 282 | { 283 | path: testPath, 284 | methods: { 285 | async get({ params }) { 286 | await sleep(100) 287 | return { 288 | status: 200, 289 | data: params.name, 290 | headers: { 'cache-control': 'max-age=0' } 291 | } 292 | }, 293 | async post() { 294 | await sleep(100) 295 | return { status: errorStatus } 296 | }, 297 | async put() { 298 | await sleep(100) 299 | throw new Error(errorMessage) 300 | }, 301 | delete() { 302 | throw new Error(errorMessage) 303 | } 304 | } 305 | }, 306 | { 307 | path: 'type-error-test', 308 | methods: { 309 | get: () => 310 | asyncResponse( 311 | 200, 312 | new Promise(resolve => resolve()) 313 | ), 314 | async post() { 315 | await sleep(100) 316 | return [errorStatus] as MockResponse 317 | } 318 | } 319 | } 320 | ] 321 | 322 | mock.setRoute(route) 323 | const { data } = await client.get(testPath, { params: { name } }) 324 | 325 | expect(data).toEqual(name) 326 | 327 | await expect(client.post(testPath)).rejects.toHaveProperty('response.status', errorStatus) 328 | await expect(client.put(testPath)).rejects.toHaveProperty('message', errorMessage) 329 | await expect(client.delete(testPath)).rejects.toHaveProperty('message', errorMessage) 330 | }) 331 | 332 | test('enable log', async () => { 333 | const spyLog = jest.spyOn(console, 'log') 334 | const testPath = '/test' 335 | const route: MockRoute = [{ path: testPath, methods: { get: () => [204] } }] 336 | 337 | mock.setRoute(route).enableLog() 338 | await client.get(testPath) 339 | 340 | expect(console.log).toHaveBeenCalled() 341 | 342 | spyLog.mockReset() 343 | mock.disableLog() 344 | await client.get(testPath) 345 | expect(console.log).not.toHaveBeenCalled() 346 | 347 | spyLog.mockReset() 348 | spyLog.mockRestore() 349 | }) 350 | }) 351 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | ### [0.19.1](https://github.com/solufa/axios-mock-server/compare/v0.19.0...v0.19.1) (2021-02-13) 6 | 7 | 8 | ### Bug Fixes 9 | 10 | * lint and typecheck error ([612b1bc](https://github.com/solufa/axios-mock-server/commit/612b1bc6c7c07240f293b6d185eef642d01ffc70)) 11 | * **deps:** [security] bump ini from 1.3.5 to 1.3.7 ([e2874d2](https://github.com/solufa/axios-mock-server/commit/e2874d2fb51cd2807860745bd6894a6844110ba7)) 12 | * **deps:** bump chokidar from 3.4.2 to 3.4.3 ([acfe4c4](https://github.com/solufa/axios-mock-server/commit/acfe4c406140ef2992f2ad20aa2e841623017fec)) 13 | 14 | 15 | ### Documentation 16 | 17 | * update README ([1e56cce](https://github.com/solufa/axios-mock-server/commit/1e56cceb414b71b1caf0e9b7a20f37f7948319a1)) 18 | 19 | ## [0.19.0](https://github.com/solufa/axios-mock-server/compare/v0.18.1...v0.19.0) (2020-08-25) 20 | 21 | 22 | ### Features 23 | 24 | * add outputFilename option ([763be9f](https://github.com/solufa/axios-mock-server/commit/763be9fd8e9359c634c919bee7b9a5c5c14e5adf)) 25 | 26 | 27 | ### Bug Fixes 28 | 29 | * **deps:** bump chokidar from 3.4.1 to 3.4.2 ([b85074a](https://github.com/solufa/axios-mock-server/commit/b85074acd8e11a1f55278fe82dbf63aedfe8e8d5)) 30 | 31 | ### [0.18.1](https://github.com/solufa/axios-mock-server/compare/v0.18.0...v0.18.1) (2020-07-28) 32 | 33 | 34 | ### Bug Fixes 35 | 36 | * version command for building depth ([fc7a7d1](https://github.com/solufa/axios-mock-server/commit/fc7a7d1f561525354deba11498c6289b4a763fb8)) 37 | 38 | ## [0.18.0](https://github.com/solufa/axios-mock-server/compare/v0.17.2...v0.18.0) (2020-07-28) 39 | 40 | 41 | ### Features 42 | 43 | * optimize build command ([0d93bde](https://github.com/solufa/axios-mock-server/commit/0d93bded96c992ef774d3bf619aa668fb5883b23)) 44 | 45 | ### [0.17.2](https://github.com/solufa/axios-mock-server/compare/v0.17.1...v0.17.2) (2020-07-26) 46 | 47 | 48 | ### Bug Fixes 49 | 50 | * version option of cli ([844ee33](https://github.com/solufa/axios-mock-server/commit/844ee337a42b12b2a613854d195498593034baed)) 51 | 52 | ### [0.17.1](https://github.com/solufa/axios-mock-server/compare/v0.17.0...v0.17.1) (2020-07-21) 53 | 54 | 55 | ### Bug Fixes 56 | 57 | * type of makeResponse ([9ed59a9](https://github.com/solufa/axios-mock-server/commit/9ed59a9069fe65b72ae7e2cc1f1e0e97badba072)) 58 | 59 | ## [0.17.0](https://github.com/solufa/axios-mock-server/compare/v0.16.3...v0.17.0) (2020-07-21) 60 | 61 | 62 | ### Bug Fixes 63 | 64 | * **deps:** [security] bump acorn from 6.4.0 to 6.4.1 ([2c96445](https://github.com/solufa/axios-mock-server/commit/2c96445028e42d623125794ed40b2075ac740458)) 65 | * **deps:** bump chokidar from 3.3.0 to 3.3.1 ([1e8a5c4](https://github.com/solufa/axios-mock-server/commit/1e8a5c42704b37ef055d587a282612ef9b223969)) 66 | * **deps:** bump chokidar from 3.3.1 to 3.4.1 ([6803a34](https://github.com/solufa/axios-mock-server/commit/6803a347589c4a42bc2a4b3b7c068b9948ff4281)) 67 | * **deps:** bump minimist from 1.2.0 to 1.2.1 ([166598b](https://github.com/solufa/axios-mock-server/commit/166598bedf1cefa737624b2c0226575cc09c1d90)) 68 | * **deps:** bump minimist from 1.2.1 to 1.2.2 ([858137a](https://github.com/solufa/axios-mock-server/commit/858137a3cfd15aa1af8a0f7942fbb0393a017f23)) 69 | * **deps:** bump minimist from 1.2.2 to 1.2.3 ([62424c0](https://github.com/solufa/axios-mock-server/commit/62424c0d6a4fd38ab49e7529ce7a822d757c0df7)) 70 | * **deps:** bump minimist from 1.2.3 to 1.2.4 ([2e37d82](https://github.com/solufa/axios-mock-server/commit/2e37d82681b3c558dfb81c97cada2359cc987290)) 71 | * **deps:** bump minimist from 1.2.4 to 1.2.5 ([cf16377](https://github.com/solufa/axios-mock-server/commit/cf1637752240ca45ac525bb91c2bf4eb146c806c)) 72 | * **deps:** bump url-search-params-polyfill from 7.0.0 to 7.0.1 ([02a074a](https://github.com/solufa/axios-mock-server/commit/02a074ae47996ede7c80a6bdeb7f67cbf4510210)) 73 | * **deps:** bump url-search-params-polyfill from 7.0.1 to 8.0.0 ([cc23d81](https://github.com/solufa/axios-mock-server/commit/cc23d8158f43b1af2fd55ba09481b3e49c073aa9)) 74 | * **deps:** bump url-search-params-polyfill from 8.0.0 to 8.1.0 ([42e6e71](https://github.com/solufa/axios-mock-server/commit/42e6e71cd98549d038eabf6e8fce99cdc8f3ab15)) 75 | 76 | 77 | ### Refactors 78 | 79 | * clarify dev command ([efcd257](https://github.com/solufa/axios-mock-server/commit/efcd257ef82f65c9b5bbb1bc2b286b6c3855930f)) 80 | * clarify listFiles ([d715a7f](https://github.com/solufa/axios-mock-server/commit/d715a7f3de7e6ba1ebc1324037be17573f4f28c6)) 81 | 82 | ### [0.16.3](https://github.com/solufa/axios-mock-server/compare/v0.16.2...v0.16.3) (2019-11-06) 83 | 84 | 85 | ### Bug Fixes 86 | 87 | * ignore empty file ([c1ea53e](https://github.com/solufa/axios-mock-server/commit/c1ea53e14aacfd05386cf6ad55486e7303003570)) 88 | * **deps:** bump chokidar from 3.2.2 to 3.2.3 ([0fec72f](https://github.com/solufa/axios-mock-server/commit/0fec72f1bee310bdaf30238dc0b16a41aa92e7c9)) 89 | * **deps:** bump chokidar from 3.2.3 to 3.3.0 ([68000b2](https://github.com/solufa/axios-mock-server/commit/68000b23b0ce1f2d3bd846322236bbd1b2985aee)) 90 | 91 | ### [0.16.2](https://github.com/solufa/axios-mock-server/compare/v0.16.1...v0.16.2) (2019-10-24) 92 | 93 | 94 | ### Bug Fixes 95 | 96 | * **cli:** ignore files other than js and ts ([fe31b37](https://github.com/solufa/axios-mock-server/commit/fe31b376cc5168ce6e749aa686f5be3fa7ab48de)) 97 | 98 | ### [0.16.1](https://github.com/solufa/axios-mock-server/compare/v0.16.0...v0.16.1) (2019-10-21) 99 | 100 | 101 | ### Bug Fixes 102 | 103 | * **factory:** add baseURL ([71fa401](https://github.com/solufa/axios-mock-server/commit/71fa401afd7ac13930bbc680e3d53f686748aa56)) 104 | 105 | ## [0.16.0](https://github.com/solufa/axios-mock-server/compare/v0.15.0...v0.16.0) (2019-10-21) 106 | 107 | 108 | ### Features 109 | 110 | * **cli:** add baseURL ([4c4dbaa](https://github.com/solufa/axios-mock-server/commit/4c4dbaa8481987fa3269f8ef7b13e9db0a533af4)) 111 | 112 | ## [0.15.0](https://github.com/solufa/axios-mock-server/compare/v0.14.1...v0.15.0) (2019-10-20) 113 | 114 | 115 | ### Features 116 | 117 | * **cli:** change file ignore pattern ([d23604d](https://github.com/solufa/axios-mock-server/commit/d23604d36bacc9aab9ce42ebfe56201086c4f587)) 118 | * **cli:** implement typed path values ([757a530](https://github.com/solufa/axios-mock-server/commit/757a530aefbecd56005cc4dac468d103491f8dbb)) 119 | 120 | 121 | ### Bug Fixes 122 | 123 | * **deps:** bump chokidar from 3.2.1 to 3.2.2 ([530ae8e](https://github.com/solufa/axios-mock-server/commit/530ae8e48f449cc63c5a9fd33d67473e9da41464)) 124 | 125 | ### [0.14.1](https://github.com/solufa/axios-mock-server/compare/v0.14.0...v0.14.1) (2019-10-14) 126 | 127 | ## [0.14.0](https://github.com/solufa/axios-mock-server/compare/v0.13.2...v0.14.0) (2019-10-12) 128 | 129 | 130 | ### Documentation 131 | 132 | * fix Dependabot badge ([f190e07](https://github.com/solufa/axios-mock-server/commit/f190e07)) 133 | 134 | 135 | ### Features 136 | 137 | * **cli:** add default input config ([c49f8a0](https://github.com/solufa/axios-mock-server/commit/c49f8a0)) 138 | * **main:** add auto path through ([da17d79](https://github.com/solufa/axios-mock-server/commit/da17d79)) 139 | 140 | ### [0.13.2](https://github.com/solufa/axios-mock-server/compare/v0.13.1...v0.13.2) (2019-10-10) 141 | 142 | 143 | ### Refactors 144 | 145 | * **axios:** move to devDependencies ([edb860e](https://github.com/solufa/axios-mock-server/commit/edb860e)) 146 | * **cli:** delete replacePathSepIfWindows ([0547552](https://github.com/solufa/axios-mock-server/commit/0547552)) 147 | 148 | ### [0.13.1](https://github.com/solufa/axios-mock-server/compare/v0.13.0...v0.13.1) (2019-10-07) 149 | 150 | 151 | ### Bug Fixes 152 | 153 | * **main:** correspond es5 for ie11 ([7ba004c](https://github.com/solufa/axios-mock-server/commit/7ba004c)) 154 | * **package.json:** conflict ([8f9deac](https://github.com/solufa/axios-mock-server/commit/8f9deac)) 155 | 156 | ## [0.13.0](https://github.com/solufa/axios-mock-server/compare/v0.12.1...v0.13.0) (2019-10-06) 157 | 158 | 159 | ### Bug Fixes 160 | 161 | * **cli:** add eslint-disable comment ([8465697](https://github.com/solufa/axios-mock-server/commit/8465697)) 162 | 163 | 164 | ### Documentation 165 | 166 | * update README.md ([9bd4e9a](https://github.com/solufa/axios-mock-server/commit/9bd4e9a)) 167 | 168 | 169 | ### Features 170 | 171 | * **cli:** change $route -> $mock ([4a8f19d](https://github.com/solufa/axios-mock-server/commit/4a8f19d)) 172 | 173 | ### [0.12.1](https://github.com/solufa/axios-mock-server/compare/v0.12.0...v0.12.1) (2019-10-02) 174 | 175 | 176 | ### Bug Fixes 177 | 178 | * **cli:** change route file write rules ([75cf691](https://github.com/solufa/axios-mock-server/commit/75cf691)) 179 | * **deps:** bump chokidar from 3.2.0 to 3.2.1 ([79f0af0](https://github.com/solufa/axios-mock-server/commit/79f0af0)) 180 | * **main:** copy response ([0dc3ba3](https://github.com/solufa/axios-mock-server/commit/0dc3ba3)) 181 | 182 | ## [0.12.0](https://github.com/solufa/axios-mock-server/compare/v0.11.0...v0.12.0) (2019-10-01) 183 | 184 | 185 | ### Bug Fixes 186 | 187 | * **deps:** bump chokidar from 3.1.1 to 3.2.0 ([bc22406](https://github.com/solufa/axios-mock-server/commit/bc22406)) 188 | 189 | 190 | ### Features 191 | 192 | * **main:** ignore directory path of baseURL ([acd6cc1](https://github.com/solufa/axios-mock-server/commit/acd6cc1)) 193 | * **mock server:** add restore method ([0883db8](https://github.com/solufa/axios-mock-server/commit/0883db8)) 194 | 195 | 196 | ### Refactors 197 | 198 | * **test:** add untransformData ([b626f9c](https://github.com/solufa/axios-mock-server/commit/b626f9c)) 199 | 200 | ## [0.11.0](https://github.com/solufa/axios-mock-server/compare/v0.10.0...v0.11.0) (2019-09-29) 201 | 202 | 203 | ### Bug Fixes 204 | 205 | * **deps:** bump chokidar from 3.0.2 to 3.1.1 ([55dd8cd](https://github.com/solufa/axios-mock-server/commit/55dd8cd)) 206 | * **jest:** ignore examples ([d2a9c75](https://github.com/solufa/axios-mock-server/commit/d2a9c75)) 207 | 208 | 209 | ### Documentation 210 | 211 | * add README.md for Japanese ([5839148](https://github.com/solufa/axios-mock-server/commit/5839148)) 212 | * fix examples ([93c90ae](https://github.com/solufa/axios-mock-server/commit/93c90ae)) 213 | * translate README.md ([8c97c12](https://github.com/solufa/axios-mock-server/commit/8c97c12)) 214 | * update .mockserverrc ([7a963c0](https://github.com/solufa/axios-mock-server/commit/7a963c0)) 215 | * update README.md ([f72bea6](https://github.com/solufa/axios-mock-server/commit/f72bea6)) 216 | * update README.md ([ffef998](https://github.com/solufa/axios-mock-server/commit/ffef998)) 217 | 218 | 219 | ### Features 220 | 221 | * **cli:** infer extension and import type ([2a545d4](https://github.com/solufa/axios-mock-server/commit/2a545d4)) 222 | * **log:** add status ([e1e849d](https://github.com/solufa/axios-mock-server/commit/e1e849d)) 223 | 224 | 225 | ### Refactors 226 | 227 | * **cli:** clarify codes ([e88a43e](https://github.com/solufa/axios-mock-server/commit/e88a43e)) 228 | * **mockserver:** set-client method ([5f4d9c3](https://github.com/solufa/axios-mock-server/commit/5f4d9c3)) 229 | 230 | ## [0.10.0](https://github.com/solufa/axios-mock-server/compare/v0.9.0...v0.10.0) (2019-09-11) 231 | 232 | 233 | ### Features 234 | 235 | * **arguments:** add params ([c228a5a](https://github.com/solufa/axios-mock-server/commit/c228a5a)) 236 | * **log:** change output format ([72fb5d4](https://github.com/solufa/axios-mock-server/commit/72fb5d4)) 237 | * **main:** add log methods ([b49b121](https://github.com/solufa/axios-mock-server/commit/b49b121)) 238 | * **response:** add Object style for type error ([4f3d8dc](https://github.com/solufa/axios-mock-server/commit/4f3d8dc)) 239 | 240 | 241 | ### Refactors 242 | 243 | * use require function without default in CommonJS ([7fe1c9e](https://github.com/solufa/axios-mock-server/commit/7fe1c9e)) 244 | 245 | 246 | ### Tests 247 | 248 | * add case of method is undefined ([9221979](https://github.com/solufa/axios-mock-server/commit/9221979)) 249 | 250 | ## [0.9.0](https://github.com/solufa/axios-mock-server/compare/v0.8.1...v0.9.0) (2019-09-08) 251 | 252 | 253 | ### Features 254 | 255 | * **mockserver:** remove 'restore' method ([bb186f9](https://github.com/solufa/axios-mock-server/commit/bb186f9)) 256 | 257 | ### [0.8.1](https://github.com/solufa/axios-mock-server/compare/v0.8.0...v0.8.1) (2019-09-07) 258 | 259 | 260 | ### Bug Fixes 261 | 262 | * **CLI:** change path '/aaa/index.js' to '/aaa' ([3667fda](https://github.com/solufa/axios-mock-server/commit/3667fda)) 263 | 264 | ## [0.8.0](https://github.com/solufa/axios-mock-server/compare/v0.7.0...v0.8.0) (2019-09-07) 265 | 266 | 267 | ### Bug Fixes 268 | 269 | * **chokidar:** change watcher config ([0552255](https://github.com/solufa/axios-mock-server/commit/0552255)) 270 | * **test:** add path pattern ([094d526](https://github.com/solufa/axios-mock-server/commit/094d526)) 271 | 272 | 273 | ### Features 274 | 275 | * **toDataURI:** delete from repository ([8aa7223](https://github.com/solufa/axios-mock-server/commit/8aa7223)) 276 | 277 | ## [0.7.0](https://github.com/solufa/axios-mock-server/compare/v0.6.0...v0.7.0) (2019-09-04) 278 | 279 | 280 | ### Bug Fixes 281 | 282 | * **adapter:** delete utils.ts ([afdcd82](https://github.com/solufa/axios-mock-server/commit/afdcd82)) 283 | * **main:** add values and params ([adb9384](https://github.com/solufa/axios-mock-server/commit/adb9384)) 284 | 285 | 286 | ### Features 287 | 288 | * **CLI:** extend multiple input ([bd1cdad](https://github.com/solufa/axios-mock-server/commit/bd1cdad)) 289 | * **main:** add factory ([3942401](https://github.com/solufa/axios-mock-server/commit/3942401)) 290 | * **main:** delete axios-mock-adapter ([d53aa6c](https://github.com/solufa/axios-mock-server/commit/d53aa6c)) 291 | 292 | ## [0.6.0](https://github.com/solufa/axios-mock-server/compare/v0.5.0...v0.6.0) (2019-09-01) 293 | 294 | 295 | ### Features 296 | 297 | * **NeDB:** delete from dependencies ([65db40d](https://github.com/solufa/axios-mock-server/commit/65db40d)) 298 | 299 | ## [0.5.0](https://github.com/solufa/axios-mock-server/compare/v0.4.0...v0.5.0) (2019-09-01) 300 | 301 | 302 | ### Bug Fixes 303 | 304 | * **main:** transform request data ([1057694](https://github.com/solufa/axios-mock-server/commit/1057694)) 305 | 306 | 307 | ### Features 308 | 309 | * **Nedb:** add async methods ([488e9f6](https://github.com/solufa/axios-mock-server/commit/488e9f6)) 310 | 311 | ## [0.4.0](https://github.com/solufa/axios-mock-server/compare/v0.3.0...v0.4.0) (2019-08-31) 312 | 313 | 314 | ### Features 315 | 316 | * **CLI:** add outputExt to config ([965f292](https://github.com/solufa/axios-mock-server/commit/965f292)) 317 | 318 | ## [0.3.0](https://github.com/solufa/axios-mock-server/compare/v0.2.0...v0.3.0) (2019-08-30) 319 | 320 | 321 | ### Features 322 | 323 | * **CLI:** add 'watch' and 'build' ([45b41b6](https://github.com/solufa/axios-mock-server/commit/45b41b6)) 324 | 325 | ## [0.2.0](https://github.com/solufa/axios-mock-server/compare/v0.1.0...v0.2.0) (2019-08-28) 326 | 327 | 328 | ### Bug Fixes 329 | 330 | * **deps:** [security] bump eslint-utils from 1.4.0 to 1.4.2 ([7f797b5](https://github.com/solufa/axios-mock-server/commit/7f797b5)) 331 | 332 | 333 | ### Documentation 334 | 335 | * fix CHANGELOG.md ([8c91ed1](https://github.com/solufa/axios-mock-server/commit/8c91ed1)) 336 | 337 | 338 | ### Features 339 | 340 | * **cli:** add command line arguments parser ([9e6e24e](https://github.com/solufa/axios-mock-server/commit/9e6e24e)) 341 | * **main:** change function to class ([248cb18](https://github.com/solufa/axios-mock-server/commit/248cb18)) 342 | 343 | ## [0.1.0](https://github.com/solufa/axios-mock-server/compare/v0.0.1...v0.1.0) (2019-08-21) 344 | 345 | 346 | ### Documentation 347 | 348 | * add badges ([c7d613b](https://github.com/solufa/axios-mock-server/commit/c7d613b)) 349 | * add GitHub templates ([97a257d](https://github.com/solufa/axios-mock-server/commit/97a257d)) 350 | 351 | 352 | ### Features 353 | 354 | * **change:** response of HTTP methods ([254c1a9](https://github.com/solufa/axios-mock-server/commit/254c1a9)) 355 | * **changing:** separated datastore ([b5bf246](https://github.com/solufa/axios-mock-server/commit/b5bf246)) 356 | * **http post:** multipart/form-data ([daaebfa](https://github.com/solufa/axios-mock-server/commit/daaebfa)) 357 | 358 | ### 0.0.1 (2019-08-18) 359 | 360 | 361 | ### Bug Fixes 362 | 363 | * test ([7c31ad6](https://github.com/solufa/axios-mock-server/commit/7c31ad6)) 364 | * url params ([a5c4631](https://github.com/solufa/axios-mock-server/commit/a5c4631)) 365 | 366 | 367 | ### Documentation 368 | 369 | * add README.md ([7e6ed38](https://github.com/solufa/axios-mock-server/commit/7e6ed38)) 370 | 371 | 372 | ### Refactors 373 | 374 | * fix implicit 'any' type ([1a9863d](https://github.com/solufa/axios-mock-server/commit/1a9863d)) 375 | -------------------------------------------------------------------------------- /docs/ja/README.md: -------------------------------------------------------------------------------- 1 |

2 | 🇺🇸English | 3 | 🇯🇵日本語 4 |

5 | 6 |

axios-mock-server

7 | 8 | [![npm version][badge-npm]][badge-npm-url] 9 | [![npm bundle size][badge-bundlephobia]][badge-bundlephobia-url] 10 | [![CircleCI][badge-ci]][badge-ci-url] 11 | [![Codecov][badge-coverage]][badge-coverage-url] 12 | [![Language grade: JavaScript][badge-lgtm]][badge-lgtm-url] 13 | [![Dependabot Status][badge-dependabot]][dependabot] 14 | [![License][badge-license]][axios-mock-server-license] 15 | 16 | [axios][axios] を使った RESTful API のモックサーバー。 17 | 18 |
19 | 目次 20 | 21 | 26 | 27 | - [特徴](#特徴) 28 | - [入門](#入門) 29 | - [インストール](#インストール) 30 | - [チュートリアル](#チュートリアル) 31 | - [API の作成](#api-の作成) 32 | - [API のビルド](#api-のビルド) 33 | - [axios のモック化](#axios-のモック化) 34 | - [使用例](#使用例) 35 | - [使い方](#使い方) 36 | - [API エンドポイントの作成](#api-エンドポイントの作成) 37 | - [axios との接続](#axios-との接続) 38 | - [デフォルト](#デフォルト) 39 | - [特定のインスタンスのみモックにする](#特定のインスタンスのみモックにする) 40 | - [関数](#関数) 41 | - [`setDelayTime(millisecond: number): void`](#setdelaytimemillisecond-number-void) 42 | - [`enableLog(): void` と `disableLog(): void`](#enablelog-void-と-disablelog-void) 43 | - [TypeScript](#typescript) 44 | - [注意事項](#注意事項) 45 | - [`.gitignore`](#gitignore) 46 | - [`@ts-ignore`, `eslint-disable`](#ts-ignore-eslint-disable) 47 | - [トラブルシューティング](#トラブルシューティング) 48 | - [TypeScript で `The expected type comes from property 'get' which is declared here on type 'MockMethods'` のエラー](#typescript-で-the-expected-type-comes-from-property-get-which-is-declared-here-on-type-mockmethods-のエラー) 49 | - [Command Line Interface のオプション](#command-line-interface-のオプション) 50 | - [設定](#設定) 51 | - [ライセンス](#ライセンス) 52 | 53 |
54 | 55 | ## 特徴 56 | 57 | - `GET`/`POST`/`PUT`/`DELETE` の API エンドポイントを数行で作成できます。 58 | - 専用のサーバーは不要です。 59 | - 静的な [JavaScript][javascript] ファイルとして SPA でも動作します。 60 | - [Node.js][nodejs] の環境でも [axios][axios] をモックにすることができます。 61 | - [Nuxt.js][nuxtjs] 同様のオートルーティング機能があり、パスの記述は必要ありません。 62 | - [TypeScript][typescript] に対応しています。 63 | 64 | ## 入門 65 | 66 | ### インストール 67 | 68 | - [npm][npm] を使ってインストール: 69 | 70 | ```sh 71 | $ npm install axios 72 | $ npm install axios-mock-server --save-dev 73 | ``` 74 | 75 | - [Yarn][yarn] を使ってインストール: 76 | 77 | ```sh 78 | $ yarn add axios 79 | $ yarn add axios-mock-server --dev 80 | ``` 81 | 82 | ### チュートリアル 83 | 84 | axios-mock-server の最もシンプルな使い方を紹介します。 85 | 86 |
87 | チュートリアルを始める 88 | 89 | #### API の作成 90 | 91 | まずはモックにするファイルを保存する `mocks` ディレクトリを作成します。 92 | 93 | ```sh 94 | $ mkdir mocks 95 | ``` 96 | 97 | 次に `mocks` ディレクトリの中に API のエンドポイントとなるファイルを作成します。 98 | `GET` リクエストでユーザーの基本情報を取得する API をモックとして定義してみましょう。 99 | 100 | `mocks/users` ディレクトリを作り `_userId.js` ファイルを作成します。 101 | 102 | ```sh 103 | $ mkdir mocks/users 104 | $ touch mocks/users/_userId.js 105 | 106 | # Windows の場合(コマンド プロンプト) 107 | > mkdir mocks\users 108 | > echo. > mocks\users\_userId.js 109 | ``` 110 | 111 | `mocks/users/_userId.js` のファイルには以下の記述を追加します。 112 | 113 | 114 | ```js 115 | // ファイル: 'mocks/users/_userId.js' 116 | const users = [{ id: 0, name: 'foo' }, { id: 1, name: 'bar' }] 117 | 118 | module.exports = { 119 | get({ values }) { 120 | return [200, users.find(user => user.id === values.userId)] 121 | } 122 | } 123 | ``` 124 | 125 | axios-mock-server のルーティングは [Nuxt.js][nuxtjs] のルーティングと同じように、`mocks` ディレクトリ内の **[JavaScript][javascript]、[TypeScript][typescript] ファイルのツリー構造に合わせて自動的に生成します。** 126 | 127 | 参考: [Routing - Nuxt.js][nuxtjs-routing] 128 | 129 | つまり `mocks/users/_userId.js` のファイルは `/users/:userId` のパスとして、**動的なルーティングを利用したエンドポイントを定義することができます。** 130 | 131 | #### API のビルド 132 | 133 | axios-mock-server は実行前にルーティングに必要なファイルをビルドして生成する必要があります。 134 | 135 | ```sh 136 | $ node_modules/.bin/axios-mock-server 137 | 138 | # Windows の場合(コマンド プロンプト) 139 | > node_modules\.bin\axios-mock-server 140 | ``` 141 | 142 | ビルドが成功すると `$mock.js` ファイルが `mocks` ディレクトリの中に生成されています。 143 | 144 | ```sh 145 | $ cat mocks/\$mock.js 146 | /* eslint-disable */ 147 | module.exports = (client) => require('axios-mock-server')([ 148 | { 149 | path: '/users/_userId', 150 | methods: require('./users/_userId') 151 | } 152 | ], client) 153 | 154 | # Windows の場合(コマンド プロンプト) 155 | > type mocks\$mock.js 156 | ``` 157 | 158 | #### axios のモック化 159 | 160 | 最後に `index.js` ファイルなどで生成した `mocks/$mock.js` ファイルをインポートし、axios-mock-server の引数に渡せば完成です。 161 | axios-mock-server はデフォルトで [axios][axios] のすべての通信をモック化します。 162 | 163 | 164 | ```js 165 | // ファイル: 'index.js' 166 | const axios = require('axios') 167 | const mock = require('./mocks/$mock.js') 168 | 169 | mock() 170 | 171 | axios.get('https://example.com/users/1').then(({ data }) => { 172 | console.log(data) 173 | }) 174 | ``` 175 | 176 | `index.js` ファイルを実行すると `{ id: 1, name: 'bar' }` が返ってくることがわかります。 177 | 178 | ```sh 179 | $ node index.js 180 | { id: 1, name: 'bar' } 181 | ``` 182 | 183 |
184 | 185 | ### 使用例 186 | 187 | axios-mock-server は **ブラウザーでの利用** から **データの永続化**、**`multipart/form-data` 形式の通信** までモックにすることができます。 188 | また、**[Nuxt.js][nuxtjs]([@nuxtjs/axios][nuxtjs-axios]) との連携** も簡単です。 189 | 190 | ソースコードは [examples][axios-mock-server-examples] を参照してください。 191 | 192 |
193 | 使用例の一覧を見る 194 | 195 | - **[browser](https://github.com/solufa/axios-mock-server/tree/develop/examples/browser)**: 196 | ブラウザーでの使用例 197 | - **[node](https://github.com/solufa/axios-mock-server/tree/develop/examples/node)**: 198 | [Node.js][nodejs](CommonJS)での使用例 199 | - **[with-nuxtjs](https://github.com/solufa/axios-mock-server/tree/develop/examples/with-nuxtjs)**: 200 | [Nuxt.js][nuxtjs] での使用例 201 | - **[with-typescript](https://github.com/solufa/axios-mock-server/tree/develop/examples/with-typescript)**: 202 | [TypeScript][typescript] での使用例 203 | 204 | **WIP** 205 | 206 | - with-in-memory-database 207 | 208 |
209 | 210 | ## 使い方 211 | 212 | ### API エンドポイントの作成 213 | 214 | 215 | ```js 216 | const users = [{ id: 0, name: 'foo' }, { id: 1, name: 'bar' }] 217 | 218 | /** 219 | * リクエストで引数として渡される変数の型定義 220 | * @typedef { Object } MockMethodParams 221 | * @property { import('axios').AxiosRequestConfig } config axios のリクエストの設定 222 | * @property {{ [key: string]: string | number }} values リクエストされた URL の動的な値(パスのアンダースコア部分) 223 | * @property {{ [key: string]: any }} params リクエストされた URL のクエリパラメータの値 224 | * @property { any } data POST などで送信されたリクエストデータ 225 | */ 226 | 227 | /** 228 | * レスポンスをオブジェクトとして返す場合の型定義 229 | * @typedef { Object } MockResponseObject 230 | * @property { number } status HTTP レスポンスステータスコード 231 | * @property { any? } data レスポンスデータ 232 | * @property {{ [key: string]: any }?} headers レスポンスヘッダー 233 | */ 234 | 235 | /** 236 | * レスポンスの型定義 237 | * @typedef { [number, any?, { [key: string]: any }?] | MockResponseObject } MockResponse 238 | */ 239 | 240 | export default { 241 | /** 242 | * GET、POST などすべてのメソッドの型は共通です 243 | * @param { MockMethodParams } 244 | * @returns { MockResponse } 245 | */ 246 | get({ values }) { 247 | return [200, users.find(user => user.id === values.userId)] 248 | }, 249 | 250 | /** 251 | * 非同期にレスポンスを返すこともできます 252 | * @param { MockMethodParams } 253 | * @returns { Promise } 254 | */ 255 | async post({ data }) { 256 | await new Promise(resolve => setTimeout(resolve, 1000)) 257 | 258 | users.push({ 259 | id: users.length, 260 | name: data.name 261 | }) 262 | 263 | return { status: 201 } 264 | } 265 | } 266 | ``` 267 | 268 | ### axios との接続 269 | 270 | #### デフォルト 271 | 272 | axios-mock-server はデフォルトで [axios][axios] のすべての通信をモック化します。 273 | 274 | 275 | ```js 276 | import axios from 'axios' 277 | import mock from './mocks/$mock.js' 278 | 279 | mock() 280 | 281 | axios.get('https://example.com/api/foo').then(response => { 282 | /* ... */ 283 | }) 284 | ``` 285 | 286 | #### 特定のインスタンスのみモックにする 287 | 288 | [axios のインスタンス][axios-instance] ごとにモック化することもできます。 289 | 290 | 291 | ```js 292 | import axios from 'axios' 293 | import mock from './mocks/$mock.js' 294 | 295 | const client = axios.create({ baseURL: 'https://example.com/api' }) 296 | 297 | mock(client) 298 | 299 | client.get('/foo').then(response => { 300 | /* ... */ 301 | }) 302 | 303 | // axios はモックされません 304 | axios.get('https://example.com/api/foo').catch(error => { 305 | console.log(error.response.status) // 404 306 | }) 307 | ``` 308 | 309 | ### 関数 310 | 311 | axios-mock-server ではいくつかの組み込み関数を利用することができます。 312 | 313 | #### `setDelayTime(millisecond: number): void` 314 | 315 | レスポンスの遅延をシミュレートします。 316 | 317 | 318 | ```js 319 | import axios from 'axios' 320 | import mock from './mocks/$mock.js' 321 | 322 | mock().setDelayTime(500) 323 | 324 | console.time() 325 | axios.get('https://example.com/api/foo').then(() => { 326 | console.timeEnd() // default: 506.590ms 327 | }) 328 | ``` 329 | 330 | #### `enableLog(): void` と `disableLog(): void` 331 | 332 | リクエストログの出力を切り替えます。 333 | 334 | 335 | ```js 336 | import axios from 'axios' 337 | import mock from './mocks/$mock.js' 338 | 339 | const mockServer = mock() 340 | 341 | ;(async () => { 342 | // 有効にする 343 | mockServer.enableLog() 344 | await axios.get('/foo', { baseURL: 'https://example.com/api', params: { bar: 'baz' } }) // 標準出力 -> [mock] get: /foo?bar=baz => 200 345 | 346 | // 無効にする 347 | mockServer.disableLog() 348 | await axios.get('/foo', { baseURL: 'https://example.com/api', params: { bar: 'baz' } }) // 標準出力 -> 349 | })() 350 | ``` 351 | 352 | ### TypeScript 353 | 354 | axios-mock-server には [TypeScript][typescript] の定義が含まれています。 355 | 356 | ### 注意事項 357 | 358 | #### `.gitignore` 359 | 360 | axios-mock-server がビルドで生成する `$mock.js`、または `$mock.ts` を [Git][git] の監視から除外してください。 361 | 362 | ```sh 363 | $ echo "\$mock.*" >> .gitignore 364 | ``` 365 | 366 | #### `@ts-ignore`, `eslint-disable` 367 | 368 | [TypeScript][typescript] のプロジェクトの場合は、`$ mock.ts` をインポートする上の行に `// @ ts-ignore` コメントを追加します。 369 | [typescript-eslint][typescript-eslint] で [`@typescript-eslint/ban-ts-ignore`][typescript-eslint-ban-ts-ignore] ルールが有効になっている場合、[ESLint][eslint] から `// ts-ignore` コメントを除外してください。 370 | 371 | 372 | ```ts 373 | // eslint-disable-next-line @typescript-eslint/ban-ts-ignore 374 | // @ts-ignore: Cannot find module 375 | import mock from './mocks/$mock' 376 | ``` 377 | 378 | ## トラブルシューティング 379 | 380 | ### TypeScript で `The expected type comes from property 'get' which is declared here on type 'MockMethods'` のエラー 381 | 382 | [TypeScript][typescript] で非同期にレスポンスを返す場合、レスポンスを配列にしようとすると型が一致しないためにエラーになります。 383 | `MockResponse` をアサーションするか、オブジェクトで返すようにしてください。 384 | 385 | エラーになる例(**axios-mock-server のビルドは通ることに注意してください!**) 386 | 387 | 388 | ```ts 389 | import { MockMethods } from 'axios-mock-server' 390 | 391 | const methods: MockMethods = { 392 | async get() { 393 | await new Promise(resolve => setTimeout(resolve, 100)) 394 | return [200, { foo: 'bar' }] // Error 395 | } 396 | } 397 | 398 | export default methods 399 | ``` 400 | 401 | `MockResponse` をアサーションして解決します。 402 | 403 | 404 | ```ts 405 | import { MockMethods, MockResponse } from 'axios-mock-server' 406 | 407 | const methods: MockMethods = { 408 | async get() { 409 | await new Promise(resolve => setTimeout(resolve, 100)) 410 | return [200, { foo: 'bar' }] as MockResponse // Type safe 411 | } 412 | } 413 | 414 | export default methods 415 | ``` 416 | 417 | レスポンスをオブジェクトにすることができればアサーションも不要です。 418 | 419 | 420 | ```ts 421 | import { MockMethods } from 'axios-mock-server' 422 | 423 | const methods: MockMethods = { 424 | async get() { 425 | await new Promise(resolve => setTimeout(resolve, 100)) 426 | return { status: 200, data: { foo: 'bar' } } // Type safe 427 | } 428 | } 429 | 430 | export default methods 431 | ``` 432 | 433 | ## Command Line Interface のオプション 434 | 435 | Command Line Interface では以下のオプションを指定することができます。 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 |
OptionTypeDefaultDescription
--config
-c
string".mockserverrc"設定ファイルまでのパスを指定します。
--watch
-w
458 | 監視モードを有効にします。
459 | API のエンドポイントとなるファイルの増減に合わせて 460 | $mock.js、または $mock.ts を再生成します。 461 |
--version
-v
axios-mock-server のバージョンを表示します。
471 | 472 | ## 設定 473 | 474 | 設定は `.mockserverrc` ファイルに JSON の構文で記述します。 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 495 | 496 | 497 | 498 | 499 | 500 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 519 | 520 | 521 |
OptionTypeDefaultDescription
inputstring | string[]"mocks" or "apis" 491 | API のエンドポイントとなるファイルが保存されているディレクトリを指定します。
492 | 複数のディレクトリを指定した場合は、それぞれのディレクトリに 493 | $mock.js、または $mock.ts を生成します。 494 |
outputExt"js" | "ts" 501 | 生成するファイルの拡張子を指定します。
502 | デフォルトは API エンドポイントのファイルの内容から自動で設定します。 503 |
outputFilenamestring"$mock.js" or "$mock.ts"生成するファイル名を指定します。
target"es6" | "cjs" 516 | 生成するモジュールのコードを指定します。
517 | デフォルトは API エンドポイントのファイルの拡張子から自動で設定します。 518 |
522 | 523 | ## ライセンス 524 | 525 | axios-mock-server は [MIT License][axios-mock-server-license] のもとで利用を許諾します。 526 | 527 | 528 | 529 | [axios-mock-server-examples]: https://github.com/solufa/axios-mock-server/tree/develop/examples 530 | [axios-mock-server-license]: https://github.com/solufa/axios-mock-server/blob/develop/LICENSE 531 | 532 | 533 | 534 | [badge-bundlephobia-url]: https://bundlephobia.com/result?p=axios-mock-server@latest 535 | [badge-bundlephobia]: https://img.shields.io/bundlephobia/min/axios-mock-server 536 | [badge-ci-url]: https://circleci.com/gh/solufa/axios-mock-server 537 | [badge-ci]: https://img.shields.io/circleci/build/github/solufa/axios-mock-server.svg?label=test 538 | [badge-coverage-url]: https://codecov.io/gh/solufa/axios-mock-server 539 | [badge-coverage]: https://img.shields.io/codecov/c/github/solufa/axios-mock-server.svg 540 | [badge-dependabot]: https://api.dependabot.com/badges/status?host=github&repo=solufa/axios-mock-server 541 | [badge-lgtm-url]: https://lgtm.com/projects/g/solufa/axios-mock-server/context:javascript 542 | [badge-lgtm]: https://img.shields.io/lgtm/grade/javascript/g/solufa/axios-mock-server.svg 543 | [badge-license]: https://img.shields.io/npm/l/axios-mock-server 544 | [badge-npm-url]: https://www.npmjs.com/package/axios-mock-server 545 | [badge-npm]: https://img.shields.io/npm/v/axios-mock-server 546 | 547 | 548 | 549 | [axios-instance]: https://github.com/axios/axios#creating-an-instance 550 | [axios]: https://github.com/axios/axios 551 | [dependabot]: https://dependabot.com 552 | [eslint]: https://eslint.org 553 | [git]: https://git-scm.com/ 554 | [javascript]: https://developer.mozilla.org/en-US/docs/Web/JavaScript 555 | [nodejs]: https://nodejs.org/ 556 | [npm]: https://www.npmjs.com/ 557 | [nuxtjs-axios]: https://github.com/nuxt-community/axios-module 558 | [nuxtjs-routing]: https://nuxtjs.org/guide/routing 559 | [nuxtjs]: https://nuxtjs.org/ 560 | [typescript-eslint-ban-ts-ignore]: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/ban-ts-ignore.md 561 | [typescript-eslint]: https://github.com/typescript-eslint/typescript-eslint 562 | [typescript]: https://www.typescriptlang.org/ 563 | [yarn]: https://yarnpkg.com/ 564 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 🇺🇸English | 3 | 🇯🇵日本語 4 |

5 | 6 |

axios-mock-server

7 | 8 | [![npm version][badge-npm]][badge-npm-url] 9 | [![npm bundle size][badge-bundlephobia]][badge-bundlephobia-url] 10 | [![CircleCI][badge-ci]][badge-ci-url] 11 | [![Codecov][badge-coverage]][badge-coverage-url] 12 | [![Language grade: JavaScript][badge-lgtm]][badge-lgtm-url] 13 | [![Dependabot Status][badge-dependabot]][dependabot] 14 | [![License][badge-license]][axios-mock-server-license] 15 | 16 | RESTful mock server using axios. 17 | 18 |
19 | Table of contents 20 | 21 | 26 | 27 | - [Features](#features) 28 | - [Getting Started](#getting-started) 29 | - [Installation](#installation) 30 | - [Tutorial](#tutorial) 31 | - [Create API](#create-api) 32 | - [Build API](#build-api) 33 | - [Mocking Axios](#mocking-axios) 34 | - [Examples](#examples) 35 | - [Usage](#usage) 36 | - [Create an API endpoint](#create-an-api-endpoint) 37 | - [Connect to axios](#connect-to-axios) 38 | - [Default](#default) 39 | - [Each instance](#each-instance) 40 | - [Functions](#functions) 41 | - [`setDelayTime(millisecond: number): void`](#setdelaytimemillisecond-number-void) 42 | - [`enableLog(): void` and `disableLog(): void`](#enablelog-void-and-disablelog-void) 43 | - [TypeScript](#typescript) 44 | - [Cautions](#cautions) 45 | - [`.gitignore`](#gitignore) 46 | - [`@ts-ignore`, `eslint-disable`](#ts-ignore-eslint-disable) 47 | - [Troubleshooting](#troubleshooting) 48 | - [`The expected type comes from property 'get' which is declared here on type 'MockMethods'` error in TypeScript](#the-expected-type-comes-from-property-get-which-is-declared-here-on-type-mockmethods-error-in-typescript) 49 | - [Command Line Interface Options](#command-line-interface-options) 50 | - [Configuration](#configuration) 51 | - [License](#license) 52 | 53 |
54 | 55 | ## Features 56 | 57 | - You can create a `GET`/`POST`/`PUT`/`DELETE` API endpoint in a few lines. 58 | - A dedicated server is not required. 59 | - It works with SPA as a static [JavaScript][javascript] file. 60 | - You can use [axios][axios] as mock-up even in [Node.js][nodejs] environment. 61 | - There is an auto-routing function similar to [Nuxt.js][nuxtjs], and no path description is required. 62 | - Supports [TypeScript][typescript]. 63 | 64 | ## Getting Started 65 | 66 | ### Installation 67 | 68 | - Using [npm][npm]: 69 | 70 | ```sh 71 | $ npm install axios 72 | $ npm install axios-mock-server --save-dev 73 | ``` 74 | 75 | - Using [Yarn][yarn]: 76 | 77 | ```sh 78 | $ yarn add axios 79 | $ yarn add axios-mock-server --dev 80 | ``` 81 | 82 | ### Tutorial 83 | 84 | Introducing the simplest use of axios-mock-server. 85 | 86 |
87 | Start the tutorial 88 | 89 | #### Create API 90 | 91 | First, create a `mocks` directory to store the files you want to mock up. 92 | 93 | ```sh 94 | $ mkdir mocks 95 | ``` 96 | 97 | Next, create an API endpoint file in the `mocks` directory. 98 | Let's define a mock API that retrieves basic user information with a `GET` request. 99 | 100 | Create a `mocks/users` directory and create a `_userId.js` file. 101 | 102 | ```sh 103 | $ mkdir mocks/users 104 | $ touch mocks/users/_userId.js 105 | 106 | # If Windows (Command Prompt) 107 | > mkdir mocks\users 108 | > echo. > mocks\users\_userId.js 109 | ``` 110 | 111 | Add the following to the `mocks/users/_userId.js` file. 112 | 113 | 114 | ```js 115 | // file: 'mocks/users/_userId.js' 116 | const users = [{ id: 0, name: 'foo' }, { id: 1, name: 'bar' }] 117 | 118 | module.exports = { 119 | get({ values }) { 120 | return [200, users.find(user => user.id === values.userId)] 121 | } 122 | } 123 | ``` 124 | 125 | The routing of axios-mock-server is **automatically generated according to the tree structure of [JavaScript][javascript] and [TypeScript][typescript] files** in the `mocks` directory in the same way as the routing of [Nuxt.js][nuxtjs]. 126 | 127 | Reference: [Routing - Nuxt.js][nuxtjs-routing] 128 | 129 | In other words, the `mocks/users/_userId.js` file **can define an endpoint using dynamic routing** as the path of `/users/:userId`. 130 | 131 | #### Build API 132 | 133 | axios-mock-server needs to build and generate the necessary files for routing before running. 134 | 135 | ```sh 136 | $ node_modules/.bin/axios-mock-server 137 | 138 | # If Windows (Command Prompt) 139 | > node_modules\.bin\axios-mock-server 140 | ``` 141 | 142 | If the build is successful, the `$mock.js` file is generated in the`mocks` directory. 143 | 144 | ```sh 145 | $ cat mocks/\$mock.js 146 | /* eslint-disable */ 147 | module.exports = (client) => require('axios-mock-server')([ 148 | { 149 | path: '/users/_userId', 150 | methods: require('./users/_userId') 151 | } 152 | ], client) 153 | 154 | # If Windows (Command Prompt) 155 | > type mocks\$mock.js 156 | ``` 157 | 158 | #### Mocking Axios 159 | 160 | Finally, import the `mocks/$mock.js` file generated by `index.js` file etc. and pass it to the argument of axios-mock-server. 161 | axios-mock-server will mock up all [axios][axios] communications by default. 162 | 163 | 164 | ```js 165 | // file: 'index.js' 166 | const axios = require('axios') 167 | const mock = require('./mocks/$mock.js') 168 | 169 | mock() 170 | 171 | axios.get('https://example.com/users/1').then(({ data }) => { 172 | console.log(data) 173 | }) 174 | ``` 175 | 176 | If you run the `index.js` file, you will see that `{ id: 1, name: 'bar' }` is returned. 177 | 178 | ```sh 179 | $ node index.js 180 | { id: 1, name: 'bar' } 181 | ``` 182 | 183 |
184 | 185 | ### Examples 186 | 187 | axios-mock-server can be used to mock up **browser usage**, **data persistence** and **`multipart/form-data` format communication**. 188 | It is also easy to link with [Nuxt.js][nuxtjs] ([@nuxtjs/axios][nuxtjs-axios]). 189 | 190 | See [examples][axios-mock-server-examples] for source code. 191 | 192 |
193 | See a list of use cases 194 | 195 | - **[browser](https://github.com/solufa/axios-mock-server/tree/develop/examples/browser)**: 196 | Use in browser 197 | - **[node](https://github.com/solufa/axios-mock-server/tree/develop/examples/node)**: 198 | Use in [Node.js][nodejs] (CommonJS) 199 | - **[with-nuxtjs](https://github.com/solufa/axios-mock-server/tree/develop/examples/with-nuxtjs)**: 200 | Using with a [Nuxt.js][nuxtjs] 201 | - **[with-typescript](https://github.com/solufa/axios-mock-server/tree/develop/examples/with-typescript)**: 202 | Using with a [TypeScript][typescript] 203 | 204 | **WIP** 205 | 206 | - with-in-memory-database 207 | 208 |
209 | 210 | ## Usage 211 | 212 | ### Create an API endpoint 213 | 214 | 215 | ```js 216 | const users = [{ id: 0, name: 'foo' }, { id: 1, name: 'bar' }] 217 | 218 | /** 219 | * Type definitions for variables passed as arguments in requests 220 | * @typedef { Object } MockMethodParams 221 | * @property { import('axios').AxiosRequestConfig } config axios request settings 222 | * @property {{ [key: string]: string | number }} values Dynamic value of the requested URL (underscore part of the path) 223 | * @property {{ [key: string]: any }} params The value of the query parameter for the requested URL 224 | * @property { any } data Request data sent by POST etc. 225 | */ 226 | 227 | /** 228 | * Type definition when response is returned as an object 229 | * @typedef { Object } MockResponseObject 230 | * @property { number } status HTTP response status code 231 | * @property { any? } data Response data 232 | * @property {{ [key: string]: any }?} headers Response header 233 | */ 234 | 235 | /** 236 | * Response type definition 237 | * @typedef { [number, any?, { [key: string]: any }?] | MockResponseObject } MockResponse 238 | */ 239 | 240 | export default { 241 | /** 242 | * All methods such as GET and POST have the same type 243 | * @param { MockMethodParams } 244 | * @returns { MockResponse } 245 | */ 246 | get({ values }) { 247 | return [200, users.find(user => user.id === values.userId)] 248 | }, 249 | 250 | /** 251 | * You can also return a response asynchronously 252 | * @param { MockMethodParams } 253 | * @returns { Promise } 254 | */ 255 | async post({ data }) { 256 | await new Promise(resolve => setTimeout(resolve, 1000)) 257 | 258 | users.push({ 259 | id: users.length, 260 | name: data.name 261 | }) 262 | 263 | return { status: 201 } 264 | } 265 | } 266 | ``` 267 | 268 | ### Connect to axios 269 | 270 | #### Default 271 | 272 | axios-mock-server will mock up all [axios][axios] communications by default. 273 | 274 | 275 | ```js 276 | import axios from 'axios' 277 | import mock from './mocks/$mock.js' 278 | 279 | mock() 280 | 281 | axios.get('https://example.com/api/foo').then(response => { 282 | /* ... */ 283 | }) 284 | ``` 285 | 286 | #### Each instance 287 | 288 | You can also mock up each [axios instance][axios-instance]. 289 | 290 | 291 | ```js 292 | import axios from 'axios' 293 | import mock from './mocks/$mock.js' 294 | 295 | const client = axios.create({ baseURL: 'https://example.com/api' }) 296 | 297 | mock(client) 298 | 299 | client.get('/foo').then(response => { 300 | /* ... */ 301 | }) 302 | 303 | // axios will not be mocked up 304 | axios.get('https://example.com/api/foo').catch(error => { 305 | console.log(error.response.status) // 404 306 | }) 307 | ``` 308 | 309 | ### Functions 310 | 311 | axios-mock-server has several built-in functions available. 312 | 313 | #### `setDelayTime(millisecond: number): void` 314 | 315 | Simulate response delay. 316 | 317 | 318 | ```js 319 | import axios from 'axios' 320 | import mock from './mocks/$mock.js' 321 | 322 | mock().setDelayTime(500) 323 | 324 | console.time() 325 | axios.get('https://example.com/api/foo').then(() => { 326 | console.timeEnd() // default: 506.590ms 327 | }) 328 | ``` 329 | 330 | #### `enableLog(): void` and `disableLog(): void` 331 | 332 | Switch request log output. 333 | 334 | 335 | ```js 336 | import axios from 'axios' 337 | import mock from './mocks/$mock.js' 338 | 339 | const mockServer = mock() 340 | 341 | ;(async () => { 342 | // To enable 343 | mockServer.enableLog() 344 | await axios.get('/foo', { baseURL: 'https://example.com/api', params: { bar: 'baz' } }) // stdout -> [mock] get: /foo?bar=baz => 200 345 | 346 | // To disable 347 | mockServer.disableLog() 348 | await axios.get('/foo', { baseURL: 'https://example.com/api', params: { bar: 'baz' } }) // stdout -> 349 | })() 350 | ``` 351 | 352 | ### TypeScript 353 | 354 | axios-mock-server includes [TypeScript][typescript] definitions. 355 | 356 | ### Cautions 357 | 358 | #### `.gitignore` 359 | 360 | Exclude `$mock.js` or `$mock.ts` generated by axios-mock-server in the build from [Git][git] monitoring. 361 | 362 | ```sh 363 | $ echo "\$mock.*" >> .gitignore 364 | 365 | # If Windows (Command Prompt) 366 | > echo $mock.* >> .gitignore 367 | ``` 368 | 369 | #### `@ts-ignore`, `eslint-disable` 370 | 371 | For [TypeScript][typescript] projects, add a `// @ ts-ignore` comment to the above line that imports`$ mock.ts`. 372 | If [`@typescript-eslint/ban-ts-ignore`][typescript-eslint-ban-ts-ignore] rule is enabled in [typescript-eslint][typescript-eslint], please exclude the `// @ ts-ignore` comment from [ESLint][eslint]. 373 | 374 | 375 | ```ts 376 | // eslint-disable-next-line @typescript-eslint/ban-ts-ignore 377 | // @ts-ignore: Cannot find module 378 | import mock from './mocks/$mock' 379 | ``` 380 | 381 | ## Troubleshooting 382 | 383 | ### `The expected type comes from property 'get' which is declared here on type 'MockMethods'` error in TypeScript 384 | 385 | When returning a response asynchronously with [TypeScript][typescript], an error occurs because the type does not match if you try to make the response an array. 386 | Assert `MockResponse` or return it as an object. 387 | 388 | Example of error (**Note that the axios-mock-server build will pass!**) 389 | 390 | 391 | ```ts 392 | import { MockMethods } from 'axios-mock-server' 393 | 394 | const methods: MockMethods = { 395 | async get() { 396 | await new Promise(resolve => setTimeout(resolve, 100)) 397 | return [200, { foo: 'bar' }] // Error 398 | } 399 | } 400 | 401 | export default methods 402 | ``` 403 | 404 | Resolve by asserting `MockResponse`. 405 | 406 | 407 | ```ts 408 | import { MockMethods, MockResponse } from 'axios-mock-server' 409 | 410 | const methods: MockMethods = { 411 | async get() { 412 | await new Promise(resolve => setTimeout(resolve, 100)) 413 | return [200, { foo: 'bar' }] as MockResponse // Type safe 414 | } 415 | } 416 | 417 | export default methods 418 | ``` 419 | 420 | If the response can be an object, no assertion is required. 421 | 422 | 423 | ```ts 424 | import { MockMethods } from 'axios-mock-server' 425 | 426 | const methods: MockMethods = { 427 | async get() { 428 | await new Promise(resolve => setTimeout(resolve, 100)) 429 | return { status: 200, data: { foo: 'bar' } } // Type safe 430 | } 431 | } 432 | 433 | export default methods 434 | ``` 435 | 436 | ## Command Line Interface Options 437 | 438 | The following options can be specified in the Command Line Interface. 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 |
OptionTypeDefaultDescription
--config
-c
string".mockserverrc"Specify the path to the configuration file.
--watch
-w
461 | Enable watch mode.
462 | Regenerate $mock.js or $mock.ts according to 463 | the increase / decrease of the API endpoint file. 464 |
--version
-v
Print axios-mock-server version.
474 | 475 | ## Configuration 476 | 477 | Settings are written in `.mockserverrc` file with JSON syntax. 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 498 | 499 | 500 | 501 | 502 | 503 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 523 | 524 | 525 |
OptionTypeDefaultDescription
inputstring | string[]"mocks" or "apis" 494 | Specify the directory where the API endpoint file is stored.
495 | If multiple directories are specified, $mock.js or 496 | $mock.ts is generated in each directory. 497 |
outputExt"js" | "ts" 504 | Specify the extension of the file to be generated.
505 | The default is set automatically from scripts of the API endpoint file. 506 |
outputFilenamestring"$mock.js" or "$mock.ts"Specify the filename to be generated.
target"es6" | "cjs" 519 | Specify the code of the module to be generated.
520 | The default is set automatically from extension of the API endpoint 521 | file. 522 |
526 | 527 | ## License 528 | 529 | axios-mock-server is licensed under a [MIT License][axios-mock-server-license]. 530 | 531 | 532 | 533 | [axios-mock-server-examples]: https://github.com/solufa/axios-mock-server/tree/develop/examples 534 | [axios-mock-server-license]: https://github.com/solufa/axios-mock-server/blob/develop/LICENSE 535 | 536 | 537 | 538 | [badge-bundlephobia-url]: https://bundlephobia.com/result?p=axios-mock-server@latest 539 | [badge-bundlephobia]: https://img.shields.io/bundlephobia/min/axios-mock-server 540 | [badge-ci-url]: https://circleci.com/gh/solufa/axios-mock-server 541 | [badge-ci]: https://img.shields.io/circleci/build/github/solufa/axios-mock-server.svg?label=test 542 | [badge-coverage-url]: https://codecov.io/gh/solufa/axios-mock-server 543 | [badge-coverage]: https://img.shields.io/codecov/c/github/solufa/axios-mock-server.svg 544 | [badge-dependabot]: https://api.dependabot.com/badges/status?host=github&repo=solufa/axios-mock-server 545 | [badge-lgtm-url]: https://lgtm.com/projects/g/solufa/axios-mock-server/context:javascript 546 | [badge-lgtm]: https://img.shields.io/lgtm/grade/javascript/g/solufa/axios-mock-server.svg 547 | [badge-license]: https://img.shields.io/npm/l/axios-mock-server 548 | [badge-npm-url]: https://www.npmjs.com/package/axios-mock-server 549 | [badge-npm]: https://img.shields.io/npm/v/axios-mock-server 550 | 551 | 552 | 553 | [axios-instance]: https://github.com/axios/axios#creating-an-instance 554 | [axios]: https://github.com/axios/axios 555 | [dependabot]: https://dependabot.com 556 | [eslint]: https://eslint.org 557 | [git]: https://git-scm.com/ 558 | [javascript]: https://developer.mozilla.org/en-US/docs/Web/JavaScript 559 | [nodejs]: https://nodejs.org/ 560 | [npm]: https://www.npmjs.com/ 561 | [nuxtjs-axios]: https://github.com/nuxt-community/axios-module 562 | [nuxtjs-routing]: https://nuxtjs.org/guide/routing 563 | [nuxtjs]: https://nuxtjs.org/ 564 | [typescript-eslint-ban-ts-ignore]: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/ban-ts-ignore.md 565 | [typescript-eslint]: https://github.com/typescript-eslint/typescript-eslint 566 | [typescript]: https://www.typescriptlang.org/ 567 | [yarn]: https://yarnpkg.com/ 568 | --------------------------------------------------------------------------------