-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: support imports using the user editor (#77)
- Loading branch information
1 parent
4966e0f
commit c7abbf4
Showing
17 changed files
with
514 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ node_modules | |
.rts2_cache_umd | ||
dist | ||
.mementorc | ||
.mementorc.json | ||
.memento-cache | ||
coverage | ||
.vscode/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import { readFile } from 'fs-extra'; | ||
import { defaultEditor } from 'env-editor'; | ||
import { spawnSync } from 'child_process'; | ||
import chalk from 'chalk'; | ||
|
||
import { ImportCurl } from '../../../domain/usecase'; | ||
import { getTestConfiguration } from '../../../test-utils/config'; | ||
import { MementoConfiguration } from '../../../configuration'; | ||
import { Logger } from '../types'; | ||
import { CliImport } from '.'; | ||
import { Request } from '../../../domain/entity'; | ||
|
||
jest.mock('child_process'); | ||
jest.mock('fs-extra'); | ||
jest.mock('env-editor'); | ||
|
||
const CACHE_DIRECTORY = 'some directory'; | ||
const TARGET_URL = 'some url'; | ||
|
||
function getTestDependencies(): { | ||
logger: Logger; | ||
importCurlUseCase: ImportCurl; | ||
config: MementoConfiguration; | ||
} { | ||
return { | ||
logger: jest.fn(), | ||
// @ts-ignore | ||
importCurlUseCase: { | ||
execute: jest.fn().mockResolvedValue(null), | ||
}, | ||
config: getTestConfiguration({ | ||
cacheDirectory: CACHE_DIRECTORY, | ||
targetUrl: TARGET_URL, | ||
}), | ||
}; | ||
} | ||
|
||
describe('import', () => { | ||
beforeEach(() => { | ||
// @ts-ignore | ||
(spawnSync as jest.Mock).mockReset(); | ||
(readFile as jest.Mock).mockReset(); | ||
(defaultEditor as jest.Mock).mockReturnValue({ binary: 'neovim' }); | ||
(readFile as jest.Mock).mockResolvedValue('# Comment\ncurl command here'); | ||
}); | ||
|
||
it('should import the curl command', async () => { | ||
// Given | ||
const dependencies = getTestDependencies(); | ||
const cliImport = new CliImport(dependencies); | ||
|
||
(dependencies.importCurlUseCase.execute as jest.Mock).mockResolvedValue( | ||
new Request('GET', '/', {}, '') | ||
); | ||
|
||
// When | ||
await cliImport.import(); | ||
|
||
//Then | ||
expect(dependencies.importCurlUseCase.execute).toHaveBeenCalledTimes(1); | ||
expect(dependencies.importCurlUseCase.execute).toHaveBeenCalledWith( | ||
'curl command here' | ||
); | ||
}); | ||
|
||
it('should use the user editor', async () => { | ||
// Given | ||
const dependencies = getTestDependencies(); | ||
const cliImport = new CliImport(dependencies); | ||
|
||
(dependencies.importCurlUseCase.execute as jest.Mock).mockResolvedValue( | ||
new Request('GET', '/', {}, '') | ||
); | ||
|
||
// When | ||
await cliImport.import(); | ||
|
||
//Then | ||
expect(spawnSync).toHaveBeenCalledTimes(1); | ||
expect(spawnSync).toHaveBeenCalledWith('neovim', [expect.any(String)], { | ||
stdio: 'inherit', | ||
}); | ||
}); | ||
|
||
it('should log an error message when an error is thrown', async () => { | ||
// Given | ||
const dependencies = getTestDependencies(); | ||
const cliImport = new CliImport(dependencies); | ||
|
||
(dependencies.importCurlUseCase.execute as jest.Mock).mockRejectedValue( | ||
new Error('Something') | ||
); | ||
|
||
// When | ||
await cliImport.import(); | ||
|
||
//Then | ||
expect(dependencies.logger).toHaveBeenCalledWith( | ||
chalk.red( | ||
'Invalid curl command provided. Please refer to the documentation for more instructions.' | ||
) | ||
); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import { spawnSync } from 'child_process'; | ||
import { tmpdir } from 'os'; | ||
import { writeFile, readFile } from 'fs-extra'; | ||
import chalk from 'chalk'; | ||
import { defaultEditor } from 'env-editor'; | ||
|
||
import { ImportCurl } from '../../../domain/usecase'; | ||
import { getRequestDirectory } from '../../../utils/path'; | ||
import { MementoConfiguration } from '../../../configuration'; | ||
import { Logger } from '../types'; | ||
|
||
const EDITOR_OUPUT_FILE = `${tmpdir}/memento-editor`; | ||
|
||
interface Dependencies { | ||
config: MementoConfiguration; | ||
importCurlUseCase: ImportCurl; | ||
logger: Logger; | ||
} | ||
|
||
export class CliImport { | ||
private config: MementoConfiguration; | ||
private importCurl: ImportCurl; | ||
private logger: Logger; | ||
|
||
public constructor({ config, importCurlUseCase, logger }: Dependencies) { | ||
this.config = config; | ||
this.importCurl = importCurlUseCase; | ||
this.logger = logger; | ||
} | ||
|
||
public async import() { | ||
const editor = defaultEditor().binary; | ||
|
||
// Reset the file content | ||
await writeFile( | ||
EDITOR_OUPUT_FILE, | ||
'# Paste your curl commmand on the next line\n' | ||
); | ||
|
||
// Get the command using the user editor | ||
spawnSync(editor, [EDITOR_OUPUT_FILE], { | ||
stdio: 'inherit', | ||
}); | ||
|
||
const editorContents = await readFile(EDITOR_OUPUT_FILE, 'utf-8'); | ||
const command = editorContents.split('\n')[1]; | ||
|
||
try { | ||
const request = await this.importCurl.execute(command); | ||
|
||
const requestDirectory = getRequestDirectory( | ||
this.config.cacheDirectory, | ||
this.config.targetUrl, | ||
request | ||
); | ||
|
||
this.logger(chalk`Request {yellow ${request.id}} has been created.`); | ||
this.logger( | ||
chalk`You may edit the request information at {yellow ${requestDirectory}}` | ||
); | ||
} catch (err) { | ||
this.logger( | ||
chalk.red`Invalid curl command provided. Please refer to the documentation for more instructions.` | ||
); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { getTestRequestRepository } from '../../test-utils/infrastructure'; | ||
import { getTestConfiguration } from '../../test-utils/config'; | ||
import { RequestRepository } from '../repository'; | ||
import { Response, Request } from '../entity'; | ||
import { ImportCurl } from './ImportCurl'; | ||
|
||
let targetUrl: string; | ||
let useCase: ImportCurl; | ||
let requestRepository: RequestRepository; | ||
|
||
beforeEach(() => { | ||
targetUrl = 'https://pokeapi.co/api/v2'; | ||
requestRepository = getTestRequestRepository(); | ||
|
||
useCase = new ImportCurl({ | ||
requestRepository, | ||
config: getTestConfiguration({ targetUrl }), | ||
}); | ||
}); | ||
|
||
it('should parse the curl command and save an empty response', async () => { | ||
// Given | ||
const curl = | ||
'curl --header "Content-Type: application/json" --request POST --data \'{"username":"xyz","password":"xyz"}\' https://pokeapi.co/api/v2/login'; | ||
|
||
// When | ||
const result = await useCase.execute(curl); | ||
|
||
// Then | ||
expect(result).toEqual( | ||
new Request( | ||
'POST', | ||
'/login', | ||
{ | ||
'content-type': 'application/json', | ||
}, | ||
'{"username":"xyz","password":"xyz"}' | ||
) | ||
); | ||
|
||
expect(requestRepository.persistResponseForRequest).toHaveBeenCalledTimes(1); | ||
expect(requestRepository.persistResponseForRequest).toHaveBeenCalledWith( | ||
new Request( | ||
'POST', | ||
'/login', | ||
{ | ||
'content-type': 'application/json', | ||
}, | ||
'{"username":"xyz","password":"xyz"}' | ||
), | ||
new Response(200, {}, Buffer.from(''), 0) | ||
); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { createRequestFromCurl } from '../../utils/request'; | ||
import { MementoConfiguration } from '../../configuration'; | ||
import { Response } from '../entity'; | ||
import { RequestRepository } from '../repository'; | ||
|
||
interface Dependencies { | ||
config: MementoConfiguration; | ||
requestRepository: RequestRepository; | ||
} | ||
|
||
export class ImportCurl { | ||
private config: MementoConfiguration; | ||
private requestRepository: RequestRepository; | ||
|
||
public constructor({ requestRepository, config }: Dependencies) { | ||
this.requestRepository = requestRepository; | ||
this.config = config; | ||
} | ||
|
||
public async execute(curlCommand: string) { | ||
const request = createRequestFromCurl(curlCommand, this.config.targetUrl); | ||
|
||
await this.requestRepository.persistResponseForRequest( | ||
request, | ||
new Response(200, {}, Buffer.from(''), 0) | ||
); | ||
|
||
return request; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
declare module 'parse-curl' { | ||
interface Headers { | ||
[key: string]: string; | ||
} | ||
type Method = | ||
| 'get' | ||
| 'GET' | ||
| 'post' | ||
| 'POST' | ||
| 'put' | ||
| 'PUT' | ||
| 'head' | ||
| 'HEAD' | ||
| 'delete' | ||
| 'DELETE' | ||
| 'options' | ||
| 'OPTIONS' | ||
| 'patch' | ||
| 'PATCH'; | ||
|
||
interface ParsedCurl { | ||
method: Method; | ||
url: string; | ||
header: Headers; | ||
body: string; | ||
} | ||
|
||
function parseCurl(curl: string): ParsedCurl; | ||
export = parseCurl; | ||
} |
Oops, something went wrong.