Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#223 into [email protected] 🐘 use Content-Type and Content-Disposition headers from response interceptor, tests for this #224

Open
wants to merge 3 commits into
base: [email protected]
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ $ npx mock-config-server
- `name` {string} name of component
- `baseUrl?` {string} part of the url that will be substituted at the beginning of rest request url (default: `'/'`)
- `configs` {Array<RestRequestConfig | GraphQLRequestConfig>} configs for mock requests, [read](#configs)
- `interceptors?` {Interceptors} functions to change request or response parameters, [read](#interceptors)
- `interceptors?` {Interceptors} functions to change request or response parameters, [read](#interceptors)

### Configs

Expand Down
62 changes: 62 additions & 0 deletions src/core/graphql/createGraphQLRoutes/createGraphQLRoutes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,68 @@ describe('createGraphQLRoutes: content', () => {
});
});

describe('createGraphQLRoutes: headers', () => {
it('Should set "application/json; charset=utf-8" Content-Type header by default for data', async () => {
const server = createServer({
graphql: {
configs: [
{
operationName: 'GetUsers',
operationType: 'query',
routes: [
{
data: 'Some text'
}
]
}
]
}
});

const query = {
query: 'query GetUsers { users { name } }'
};

const response = await request(server).get('/').query(query);

expect(response.statusCode).toBe(200);
expect(response.headers['content-type']).toBe('application/json; charset=utf-8');
});

it('Should use Content-Type header from response interceptor for data', async () => {
const server = createServer({
graphql: {
configs: [
{
operationName: 'GetUsers',
operationType: 'query',
routes: [
{
data: 'Some text',
interceptors: {
response: (data, { appendHeader }) => {
appendHeader('content-type', 'text/plain; charset=utf-8');
return data;
}
}
}
]
}
]
}
});

const query = {
query: 'query GetUsers { users { name } }'
};

const response = await request(server).get('/').query(query);

expect(response.statusCode).toBe(200);
expect(response.headers['content-type']).toBe('text/plain; charset=utf-8');
});
});

describe('createGraphQLRoutes: settings', () => {
it('Should correctly delay response based on delay setting', async () => {
const delay = 1000;
Expand Down
5 changes: 4 additions & 1 deletion src/core/graphql/createGraphQLRoutes/createGraphQLRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,10 @@ export const createGraphQLRoutes = ({
await sleep(matchedRouteConfig.settings.delay);
}

return response.json(data);
if (!response.getHeader('content-type')) {
return response.json(data);
}
response.send(data);
};

router.route('/').get(asyncHandler(graphqlMiddleware));
Expand Down
157 changes: 156 additions & 1 deletion src/core/rest/createRestRoutes/createRestRoutes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ describe('createRestRoutes: content', () => {
fs.rmSync(tmpDirPath, { recursive: true, force: true });
});

it('should call response interceptor with Buffer as the first argument property when return a file', async () => {
it('Should call response interceptor with Buffer as the first argument property when return a file', async () => {
const tmpDirPath = createTmpDir();
const pathToFile = path.join(tmpDirPath, './data.json') as `${string}.json`;
const dataInFile = JSON.stringify({ standName: 'The World' });
Expand Down Expand Up @@ -485,6 +485,161 @@ describe('createRestRoutes: content', () => {
});
});

describe('createRestRoutes: headers', () => {
it('Should set "application/json; charset=utf-8" Content-Type header by default for data', async () => {
const server = createServer({
rest: {
configs: [
{
path: '/users',
method: 'get',
routes: [
{
data: 'Some text'
}
]
}
]
}
});

const response = await request(server).get('/users');

expect(response.statusCode).toBe(200);
expect(response.headers['content-type']).toBe('application/json; charset=utf-8');
});

it('Should use Content-Type header from response interceptor for data', async () => {
const server = createServer({
rest: {
configs: [
{
path: '/users',
method: 'get',
routes: [
{
data: 'Some text',
interceptors: {
response: (data, { appendHeader }) => {
appendHeader('content-type', 'text/plain; charset=utf-8');
return data;
}
}
}
]
}
]
}
});

const response = await request(server).get('/users');

expect(response.statusCode).toBe(200);
expect(response.headers['content-type']).toBe('text/plain; charset=utf-8');
});

it('Should set correct Content-Type and Content-Disposition headers by default for file', async () => {
const tmpDirPath = createTmpDir();
const pathToJSONFile = path.join(tmpDirPath, './jsonData.json');
fs.writeFileSync(pathToJSONFile, JSON.stringify({ some: 'data' }));
const pathToTxtFile = path.join(tmpDirPath, './txtData.txt');
fs.writeFileSync(pathToTxtFile, 'Some text');
const pathToHtmlFile = path.join(tmpDirPath, './htmlData.html');
fs.writeFileSync(pathToHtmlFile, '<html lang="en"><body>Some HTML</body></html>');

const server = createServer({
rest: {
configs: [
{
path: '/users',
method: 'get',
routes: [
{
entities: {
query: {
type: 'json'
}
},
file: pathToJSONFile
},
{
entities: {
query: {
type: 'txt'
}
},
file: pathToTxtFile
},
{
entities: {
query: {
type: 'html'
}
},
file: pathToHtmlFile
}
]
}
]
}
});

const jsonResponse = await request(server).get('/users').query({ type: 'json' });

expect(jsonResponse.statusCode).toBe(200);
expect(jsonResponse.headers['content-type']).toBe('application/json; charset=utf-8');

const txtResponse = await request(server).get('/users').query({ type: 'txt' });

expect(txtResponse.statusCode).toBe(200);
expect(txtResponse.headers['content-type']).toBe('text/plain; charset=utf-8');

const htmlResponse = await request(server).get('/users').query({ type: 'html' });

expect(htmlResponse.statusCode).toBe(200);
expect(htmlResponse.headers['content-type']).toBe('text/html; charset=utf-8');

fs.rmSync(tmpDirPath, { recursive: true, force: true });
});

it('Should use Content-Type and Content-Disposition headers from response interceptor for file', async () => {
const tmpDirPath = createTmpDir();
const pathToFile = path.join(tmpDirPath, './data.json');
fs.writeFileSync(pathToFile, JSON.stringify({ some: 'data' }));

const server = createServer({
rest: {
configs: [
{
path: '/users',
method: 'get',
routes: [
{
file: pathToFile,
interceptors: {
response: (data, { appendHeader }) => {
appendHeader('content-type', 'text/plain; charset=utf-8');
appendHeader('content-disposition', 'filename=someData.txt');
return data;
}
}
}
]
}
]
}
});

const response = await request(server).get('/users');

expect(response.statusCode).toBe(200);
expect(response.headers['content-type']).toBe('text/plain; charset=utf-8');
expect(response.headers['content-disposition']).toBe('filename=someData.txt');

fs.rmSync(tmpDirPath, { recursive: true, force: true });
});
});

describe('createRestRoutes: settings', () => {
it('Should correctly delay response based on delay setting', async () => {
const delay = 1000;
Expand Down
17 changes: 13 additions & 4 deletions src/core/rest/createRestRoutes/createRestRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,12 +249,21 @@ export const createRestRoutes = ({
}
// ✅ important: replace backslashes because windows can use them in file path
const fileName = data.path.replaceAll('\\', '/').split('/').at(-1)!;
const fileExtension = fileName.split('.').at(-1)!;
response.type(fileExtension);
response.set('Content-Disposition', `filename=${fileName}`);

if (!response.getHeader('content-disposition')) {
response.set('content-disposition', `filename=${fileName}`);
}
if (!response.getHeader('content-type')) {
const fileExtension = fileName.split('.').at(-1)!;
response.type(fileExtension);
}

return response.send(data.file);
}
response.json(data);
if (!response.getHeader('content-type')) {
return response.json(data);
}
response.send(data);
})
);
});
Expand Down