HATEOAS-first backend framework.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

default.test.ts 3.6 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. import {
  2. describe,
  3. beforeAll,
  4. afterAll,
  5. it,
  6. expect,
  7. vi, Mock,
  8. } from 'vitest';
  9. import {
  10. app,
  11. Endpoint,
  12. Operation,
  13. } from '../../src/common';
  14. import {DataSource, DataSourceQuery, EmplaceDetails, Server} from '../../src/backend';
  15. import {Client} from '../../src/client';
  16. import {server} from '../../src/extenders/http/backend';
  17. import {client} from '../../src/extenders/http/client';
  18. import {composeRecipes} from '../../src/common/recipe';
  19. import {addResourceRecipe, ResourceItemFetchedResponse} from '../../src/recipes/resource';
  20. describe('default', () => {
  21. let theClient: Client;
  22. let theServer: Server;
  23. let theRawEndpoint: Endpoint;
  24. let theOperation: Operation;
  25. let dataSource: Record<keyof DataSource, Mock>;
  26. beforeAll(() => {
  27. dataSource = {
  28. create: vi.fn(async (data) => data),
  29. getById: vi.fn(async () => ({})),
  30. delete: vi.fn(),
  31. emplace: vi.fn(async () => [{}, { isCreated: false }]),
  32. getMultiple: vi.fn(async () => []),
  33. getSingle: vi.fn(async () => ({})),
  34. getTotalCount: vi.fn(async () => 1),
  35. newId: vi.fn(async () => 1),
  36. patch: vi.fn(async (id, data) => ({ ...data, id })),
  37. initialize: vi.fn(async () => {}),
  38. };
  39. });
  40. afterAll(() => {
  41. dataSource.getById.mockReset();
  42. });
  43. beforeAll(async () => {
  44. const {
  45. app: theApp,
  46. operations,
  47. backend: theBackend,
  48. } = composeRecipes([
  49. addResourceRecipe({ endpointName: 'users', dataSource, }),
  50. addResourceRecipe({ endpointName: 'posts', dataSource, })
  51. ])({
  52. app: app({
  53. name: 'default' as const,
  54. }),
  55. });
  56. theRawEndpoint = theApp.endpoints.get('users');
  57. theOperation = operations.fetch;
  58. theServer = server({
  59. backend: theBackend,
  60. });
  61. const connectionParams = {
  62. port: 3001,
  63. };
  64. await theServer.serve(connectionParams);
  65. theClient = client({
  66. app: theApp,
  67. });
  68. await theClient.connect(connectionParams);
  69. });
  70. afterAll(async () => {
  71. await theClient.disconnect();
  72. await theServer.close();
  73. });
  74. it('works', async () => {
  75. // TODO create wrapper for fetch's Response here
  76. //
  77. // should we create a helper object to process client-side received response from server's sent response?
  78. //
  79. // the motivation is to remove the manual deserialization from the client (provide serialization on the response
  80. // object so as the client is not limited to .text(), .json(), .arrayBuffer() etc)
  81. const responseRaw = await theClient
  82. .at(theRawEndpoint)
  83. .makeRequest(
  84. theOperation
  85. .search({
  86. foo: 'bar',
  87. })
  88. );
  89. const response = ResourceItemFetchedResponse.fromFetchResponse(responseRaw);
  90. expect(response).toHaveProperty('statusCode', 200);
  91. expect(response).toHaveProperty('statusMessage', 'Resource Collection Fetched');
  92. });
  93. it('works for items', async () => {
  94. // TODO create wrapper for fetch's Response here
  95. //
  96. // should we create a helper object to process client-side received response from server's sent response?
  97. //
  98. // the motivation is to remove the manual deserialization from the client (provide serialization on the response
  99. // object so as the client is not limited to .text(), .json(), .arrayBuffer() etc)
  100. const responseRaw = await theClient
  101. .at(theRawEndpoint, { resourceId: 3 })
  102. // TODO how to inject extra data (e.g. headers, body) in the operation (e.g. auth)?
  103. .makeRequest(
  104. theOperation
  105. .search({
  106. foo: 'bar',
  107. }) // allow multiple calls of .search() to add to search params
  108. );
  109. const response = ResourceItemFetchedResponse.fromFetchResponse(responseRaw);
  110. expect(response).toHaveProperty('statusCode', 200);
  111. expect(response).toHaveProperty('statusMessage', 'Resource Item Fetched');
  112. });
  113. });