@entifix/testing-e2e 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/fixtures/entity-backend.d.ts.map +1 -1
- package/dist/fixtures/entity-backend.js +12 -20
- package/dist/fixtures/entity-backend.js.map +1 -1
- package/dist/fixtures/entity-handlers.d.ts.map +1 -1
- package/dist/fixtures/entity-handlers.js +11 -4
- package/dist/fixtures/entity-handlers.js.map +1 -1
- package/package.json +12 -12
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entity-backend.d.ts","sourceRoot":"","sources":["../../src/fixtures/entity-backend.ts"],"names":[],"mappings":"AASA,OAAO,EAEL,KAAK,MAAM,EACX,KAAK,iBAAiB,EACtB,KAAK,QAAQ,
|
|
1
|
+
{"version":3,"file":"entity-backend.d.ts","sourceRoot":"","sources":["../../src/fixtures/entity-backend.ts"],"names":[],"mappings":"AASA,OAAO,EAEL,KAAK,MAAM,EACX,KAAK,iBAAiB,EACtB,KAAK,QAAQ,EAYd,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,KAAK,WAAW,EAEjB,MAAM,+BAA+B,CAAC;AAGvC;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;CACxB;AAED,8EAA8E;AAC9E,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEjD,MAAM,WAAW,oBAAoB;IACnC,mDAAmD;IACnD,IAAI,CAAC,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,aAAa;IAC5B,sEAAsE;IACtE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,0EAA0E;IAC1E,IAAI,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IACxD,iFAAiF;IACjF,MAAM,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IAC1D,4BAA4B;IAC5B,GAAG,CAAC,EAAE,EAAE,QAAQ,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IAC5C,2EAA2E;IAC3E,IAAI,CAAC,IAAI,EAAE,aAAa,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;IAC5C,wEAAwE;IACxE,IAAI,IAAI,UAAU,EAAE,CAAC;IACrB,yDAAyD;IACzD,QAAQ,CAAC,EAAE,EAAE,WAAW,CAAC;CAC1B;AAcD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,iBAAiB,GAAI,OAAO,SAAS,MAAM,EACtD,mBAAmB,iBAAiB,CAAC,OAAO,CAAC,EAC7C,WAAe,oBAAyB,KACvC,aAsIF,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
2
|
import { EntityFacetCounterTag, EntityIdTag, EntityLoadRequestTag, EntityRepositoryTag, facetCountsUCFactory, getUCFactory, loadUCFactory } from '@entifix/business';
|
|
3
|
-
import { envelopeEntityName, makeEntityEnvelope, makeEntityFacetsEnvelope, makeEntityPageEnvelope, parseFacetQueryParams, parseLoadRequestParams } from '@entifix/core';
|
|
3
|
+
import { envelopeEntityName, Internal, InvalidQuery, makeEntityEnvelope, makeEntityFacetsEnvelope, makeEntityPageEnvelope, NotFound, parseFacetQueryParams, parseLoadRequestParams, problemOf } from '@entifix/core';
|
|
4
4
|
import { makeMongoFacetCounter, makeMongoRepository } from '@entifix/mongo';
|
|
5
5
|
import { makeFakeMongoDb } from '@entifix/testing-unit/drivers';
|
|
6
6
|
import { Effect } from 'effect';
|
|
@@ -82,10 +82,9 @@ const entityLinks = (key, id)=>[
|
|
|
82
82
|
// reporting it verbatim is more useful than hiding it behind a 500.
|
|
83
83
|
return {
|
|
84
84
|
status: 400,
|
|
85
|
-
body: {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
85
|
+
body: problemOf(new InvalidQuery({
|
|
86
|
+
reason: error.message
|
|
87
|
+
}))
|
|
89
88
|
};
|
|
90
89
|
}
|
|
91
90
|
try {
|
|
@@ -99,10 +98,7 @@ const entityLinks = (key, id)=>[
|
|
|
99
98
|
// request was valid, the store was not reachable.
|
|
100
99
|
return {
|
|
101
100
|
status: 500,
|
|
102
|
-
body:
|
|
103
|
-
error: 'request failed',
|
|
104
|
-
detail: String(error)
|
|
105
|
-
}
|
|
101
|
+
body: problemOf(new Internal())
|
|
106
102
|
};
|
|
107
103
|
}
|
|
108
104
|
},
|
|
@@ -115,10 +111,9 @@ const entityLinks = (key, id)=>[
|
|
|
115
111
|
} catch (error) {
|
|
116
112
|
return {
|
|
117
113
|
status: 400,
|
|
118
|
-
body: {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
114
|
+
body: problemOf(new InvalidQuery({
|
|
115
|
+
reason: error.message
|
|
116
|
+
}))
|
|
122
117
|
};
|
|
123
118
|
}
|
|
124
119
|
try {
|
|
@@ -130,10 +125,7 @@ const entityLinks = (key, id)=>[
|
|
|
130
125
|
} catch (error) {
|
|
131
126
|
return {
|
|
132
127
|
status: 500,
|
|
133
|
-
body:
|
|
134
|
-
error: 'request failed',
|
|
135
|
-
detail: String(error)
|
|
136
|
-
}
|
|
128
|
+
body: problemOf(new Internal())
|
|
137
129
|
};
|
|
138
130
|
}
|
|
139
131
|
},
|
|
@@ -141,9 +133,9 @@ const entityLinks = (key, id)=>[
|
|
|
141
133
|
const entity = await run(getUCFactory().pipe(Effect.provideService(EntityRepositoryTag, repository), Effect.provideService(EntityIdTag, id), Effect.option));
|
|
142
134
|
return entity._tag === 'None' ? {
|
|
143
135
|
status: 404,
|
|
144
|
-
body: {
|
|
145
|
-
|
|
146
|
-
}
|
|
136
|
+
body: problemOf(new NotFound({
|
|
137
|
+
entity: key
|
|
138
|
+
}))
|
|
147
139
|
} : {
|
|
148
140
|
status: 200,
|
|
149
141
|
body: makeEntityEnvelope(entityConstructor, entity.value, entityLinks(key, id))
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/fixtures/entity-backend.ts"],"sourcesContent":["import {\n EntityFacetCounterTag,\n EntityIdTag,\n EntityLoadRequestTag,\n EntityRepositoryTag,\n facetCountsUCFactory,\n getUCFactory,\n loadUCFactory,\n} from '@entifix/business';\nimport {\n type EntifixEnvelopeLink,\n type Entity,\n type EntityConstructor,\n type EntityId,\n type EntityLoadRequest,\n envelopeEntityName,\n makeEntityEnvelope,\n makeEntityFacetsEnvelope,\n makeEntityPageEnvelope,\n parseFacetQueryParams,\n parseLoadRequestParams,\n} from '@entifix/core';\nimport { makeMongoFacetCounter, makeMongoRepository } from '@entifix/mongo';\nimport {\n type FakeMongoDb,\n makeFakeMongoDb,\n} from '@entifix/testing-unit/drivers';\nimport { Effect } from 'effect';\n\n/**\n * A response as an HTTP transport would send it. `body` is an entifix envelope\n * or an error record; it stays `unknown` here so the backend is not coupled to\n * one transport's body type.\n */\nexport interface BackendResponse {\n readonly status: number;\n readonly body: unknown;\n}\n\n/** Rows as they are stored — the entity wire shape, exactly like the seed. */\nexport type BackendRow = Record<string, unknown>;\n\nexport interface EntityBackendOptions {\n /** Initial documents, in the entity wire shape. */\n seed?: ReadonlyArray<BackendRow>;\n}\n\nexport interface EntityBackend {\n /** The entity `key` — collection name and REST path segment alike. */\n readonly key: string;\n /** `GET /api/<key>?<search>` — filtering, sorting and paging included. */\n list(search: URLSearchParams): Promise<BackendResponse>;\n /** `GET /api/<key>/$facets?<search>` — the counts beside a listing's filters. */\n facets(search: URLSearchParams): Promise<BackendResponse>;\n /** `GET /api/<key>/:id`. */\n get(id: EntityId): Promise<BackendResponse>;\n /** Replaces the stored rows, so one fixture can serve several journeys. */\n seed(rows: ReadonlyArray<BackendRow>): void;\n /** The rows currently stored, for assertions about what a write did. */\n rows(): BackendRow[];\n /** The underlying driver fake, for failure injection. */\n readonly db: FakeMongoDb;\n}\n\nconst collectionLinks = (key: string): EntifixEnvelopeLink[] => [\n { rel: 'self', href: `/api/${key}`, method: 'GET' },\n { rel: 'create', href: `/api/${key}`, method: 'POST' },\n];\n\nconst entityLinks = (key: string, id: EntityId): EntifixEnvelopeLink[] => [\n { rel: 'self', href: `/api/${key}/${String(id)}`, method: 'GET' },\n { rel: 'list', href: `/api/${key}`, method: 'GET' },\n { rel: 'update', href: `/api/${key}/${String(id)}`, method: 'PUT' },\n { rel: 'delete', href: `/api/${key}/${String(id)}`, method: 'DELETE' },\n];\n\n/**\n * A read backend for one entity, assembled from the PRODUCTION query pipeline:\n *\n * ```\n * parseLoadRequestParams → loadUCFactory → makeMongoRepository → fake driver\n * (core: RSQL + the (business: (mongo-client: (testing-unit)\n * filterable/sortable the use-case) filter translation)\n * allowlist)\n * ```\n *\n * Nothing here re-implements query semantics. That is the whole point: a mock\n * backend that answers a filter with \"all the rows\" makes a green `mock` run\n * meaningless, and a mock backend that implements its *own* RSQL makes the two\n * profiles disagree the first time an operator is added. Because the real\n * pipeline runs, `mock` and `live` agree on filtering, sorting, paging, and on\n * the `400 invalid query` the metadata allowlist produces.\n *\n * Writes are deliberately absent: a `POST` in the admin service is a\n * *transaction* answering `202`, and a fixture that answered `201` instead\n * would be a lie about the protocol rather than a stand-in for it.\n */\nexport const makeEntityBackend = <TEntity extends Entity>(\n entityConstructor: EntityConstructor<TEntity>,\n { seed = [] }: EntityBackendOptions = {},\n): EntityBackend => {\n const key = envelopeEntityName(entityConstructor);\n const db = makeFakeMongoDb({ [key]: seed.map(row => ({ ...row })) });\n const repository = makeMongoRepository(\n // The driver fake is typed `unknown` so `testing-unit` need not depend on\n // the mongodb types; the cast is the documented way to hand it over.\n db.db as Parameters<typeof makeMongoRepository>[0],\n entityConstructor,\n );\n\n const counter = makeMongoFacetCounter(\n db.db as Parameters<typeof makeMongoFacetCounter>[0],\n entityConstructor,\n );\n\n const run = <TValue, TError>(\n effect: Effect.Effect<TValue, TError, never>,\n ): Promise<TValue> => Effect.runPromise(effect);\n\n return {\n key,\n\n list: async search => {\n let request: EntityLoadRequest;\n try {\n request = parseLoadRequestParams(\n entityConstructor,\n search,\n ) as unknown as EntityLoadRequest;\n } catch (error) {\n // The same 400 the service answers: an unparseable expression, or a\n // member the entity never declared filterable/sortable. The codec only\n // ever throws `EntifixBuildError` here, so there is no second case to\n // discriminate — anything else would be a bug in the codec, and\n // reporting it verbatim is more useful than hiding it behind a 500.\n return {\n status: 400,\n body: { error: 'invalid query', detail: String(error) },\n };\n }\n\n try {\n const page = await run(\n loadUCFactory<TEntity>().pipe(\n Effect.provideService(EntityRepositoryTag, repository),\n Effect.provideService(EntityLoadRequestTag, request),\n ),\n );\n\n return {\n status: 200,\n body: makeEntityPageEnvelope(\n entityConstructor,\n page,\n collectionLinks(key),\n ),\n };\n } catch (error) {\n // A repository that fails is a 500, exactly as in the service: the\n // request was valid, the store was not reachable.\n return {\n status: 500,\n body: { error: 'request failed', detail: String(error) },\n };\n }\n },\n\n // The same production pipeline as `list`: the protocol's parser and its\n // allowlist, the use case, and the Mongo counter over the fake driver.\n facets: async search => {\n let queries;\n try {\n queries = parseFacetQueryParams(entityConstructor, search);\n } catch (error) {\n return {\n status: 400,\n body: { error: 'invalid query', detail: String(error) },\n };\n }\n\n try {\n const counts = await run(\n facetCountsUCFactory(queries).pipe(\n Effect.provideService(EntityFacetCounterTag, counter),\n ),\n );\n return {\n status: 200,\n body: makeEntityFacetsEnvelope(entityConstructor, counts),\n };\n } catch (error) {\n return {\n status: 500,\n body: { error: 'request failed', detail: String(error) },\n };\n }\n },\n\n get: async id => {\n const entity = await run(\n getUCFactory<TEntity>().pipe(\n Effect.provideService(EntityRepositoryTag, repository),\n Effect.provideService(EntityIdTag, id),\n Effect.option,\n ),\n );\n\n return entity._tag === 'None'\n ? { status: 404, body: { message: `${key} not found` } }\n : {\n status: 200,\n body: makeEntityEnvelope(\n entityConstructor,\n entity.value,\n entityLinks(key, id),\n ),\n };\n },\n\n seed: rows => {\n db.seed(\n key,\n rows.map(row => ({ ...row })),\n );\n },\n\n rows: () => db.read(key),\n\n db,\n };\n};\n"],"names":["EntityFacetCounterTag","EntityIdTag","EntityLoadRequestTag","EntityRepositoryTag","facetCountsUCFactory","getUCFactory","loadUCFactory","envelopeEntityName","makeEntityEnvelope","makeEntityFacetsEnvelope","makeEntityPageEnvelope","parseFacetQueryParams","parseLoadRequestParams","makeMongoFacetCounter","makeMongoRepository","makeFakeMongoDb","Effect","collectionLinks","key","rel","href","method","entityLinks","id","String","makeEntityBackend","entityConstructor","seed","db","map","row","repository","counter","run","effect","runPromise","list","search","request","error","status","body","detail","page","pipe","provideService","facets","queries","counts","get","entity","option","_tag","message","value","rows","read"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/fixtures/entity-backend.ts"],"sourcesContent":["import {\n EntityFacetCounterTag,\n EntityIdTag,\n EntityLoadRequestTag,\n EntityRepositoryTag,\n facetCountsUCFactory,\n getUCFactory,\n loadUCFactory,\n} from '@entifix/business';\nimport {\n type EntifixEnvelopeLink,\n type Entity,\n type EntityConstructor,\n type EntityId,\n type EntityLoadRequest,\n envelopeEntityName,\n Internal,\n InvalidQuery,\n makeEntityEnvelope,\n makeEntityFacetsEnvelope,\n makeEntityPageEnvelope,\n NotFound,\n parseFacetQueryParams,\n parseLoadRequestParams,\n problemOf,\n} from '@entifix/core';\nimport { makeMongoFacetCounter, makeMongoRepository } from '@entifix/mongo';\nimport {\n type FakeMongoDb,\n makeFakeMongoDb,\n} from '@entifix/testing-unit/drivers';\nimport { Effect } from 'effect';\n\n/**\n * A response as an HTTP transport would send it. `body` is an entifix envelope\n * or an error record; it stays `unknown` here so the backend is not coupled to\n * one transport's body type.\n */\nexport interface BackendResponse {\n readonly status: number;\n readonly body: unknown;\n}\n\n/** Rows as they are stored — the entity wire shape, exactly like the seed. */\nexport type BackendRow = Record<string, unknown>;\n\nexport interface EntityBackendOptions {\n /** Initial documents, in the entity wire shape. */\n seed?: ReadonlyArray<BackendRow>;\n}\n\nexport interface EntityBackend {\n /** The entity `key` — collection name and REST path segment alike. */\n readonly key: string;\n /** `GET /api/<key>?<search>` — filtering, sorting and paging included. */\n list(search: URLSearchParams): Promise<BackendResponse>;\n /** `GET /api/<key>/$facets?<search>` — the counts beside a listing's filters. */\n facets(search: URLSearchParams): Promise<BackendResponse>;\n /** `GET /api/<key>/:id`. */\n get(id: EntityId): Promise<BackendResponse>;\n /** Replaces the stored rows, so one fixture can serve several journeys. */\n seed(rows: ReadonlyArray<BackendRow>): void;\n /** The rows currently stored, for assertions about what a write did. */\n rows(): BackendRow[];\n /** The underlying driver fake, for failure injection. */\n readonly db: FakeMongoDb;\n}\n\nconst collectionLinks = (key: string): EntifixEnvelopeLink[] => [\n { rel: 'self', href: `/api/${key}`, method: 'GET' },\n { rel: 'create', href: `/api/${key}`, method: 'POST' },\n];\n\nconst entityLinks = (key: string, id: EntityId): EntifixEnvelopeLink[] => [\n { rel: 'self', href: `/api/${key}/${String(id)}`, method: 'GET' },\n { rel: 'list', href: `/api/${key}`, method: 'GET' },\n { rel: 'update', href: `/api/${key}/${String(id)}`, method: 'PUT' },\n { rel: 'delete', href: `/api/${key}/${String(id)}`, method: 'DELETE' },\n];\n\n/**\n * A read backend for one entity, assembled from the PRODUCTION query pipeline:\n *\n * ```\n * parseLoadRequestParams → loadUCFactory → makeMongoRepository → fake driver\n * (core: RSQL + the (business: (mongo-client: (testing-unit)\n * filterable/sortable the use-case) filter translation)\n * allowlist)\n * ```\n *\n * Nothing here re-implements query semantics. That is the whole point: a mock\n * backend that answers a filter with \"all the rows\" makes a green `mock` run\n * meaningless, and a mock backend that implements its *own* RSQL makes the two\n * profiles disagree the first time an operator is added. Because the real\n * pipeline runs, `mock` and `live` agree on filtering, sorting, paging, and on\n * the `400 invalid query` the metadata allowlist produces.\n *\n * Writes are deliberately absent: a `POST` in the admin service is a\n * *transaction* answering `202`, and a fixture that answered `201` instead\n * would be a lie about the protocol rather than a stand-in for it.\n */\nexport const makeEntityBackend = <TEntity extends Entity>(\n entityConstructor: EntityConstructor<TEntity>,\n { seed = [] }: EntityBackendOptions = {},\n): EntityBackend => {\n const key = envelopeEntityName(entityConstructor);\n const db = makeFakeMongoDb({ [key]: seed.map(row => ({ ...row })) });\n const repository = makeMongoRepository(\n // The driver fake is typed `unknown` so `testing-unit` need not depend on\n // the mongodb types; the cast is the documented way to hand it over.\n db.db as Parameters<typeof makeMongoRepository>[0],\n entityConstructor,\n );\n\n const counter = makeMongoFacetCounter(\n db.db as Parameters<typeof makeMongoFacetCounter>[0],\n entityConstructor,\n );\n\n const run = <TValue, TError>(\n effect: Effect.Effect<TValue, TError, never>,\n ): Promise<TValue> => Effect.runPromise(effect);\n\n return {\n key,\n\n list: async search => {\n let request: EntityLoadRequest;\n try {\n request = parseLoadRequestParams(\n entityConstructor,\n search,\n ) as unknown as EntityLoadRequest;\n } catch (error) {\n // The same 400 the service answers: an unparseable expression, or a\n // member the entity never declared filterable/sortable. The codec only\n // ever throws `EntifixBuildError` here, so there is no second case to\n // discriminate — anything else would be a bug in the codec, and\n // reporting it verbatim is more useful than hiding it behind a 500.\n return {\n status: 400,\n body: problemOf(\n new InvalidQuery({ reason: (error as Error).message }),\n ),\n };\n }\n\n try {\n const page = await run(\n loadUCFactory<TEntity>().pipe(\n Effect.provideService(EntityRepositoryTag, repository),\n Effect.provideService(EntityLoadRequestTag, request),\n ),\n );\n\n return {\n status: 200,\n body: makeEntityPageEnvelope(\n entityConstructor,\n page,\n collectionLinks(key),\n ),\n };\n } catch (error) {\n // A repository that fails is a 500, exactly as in the service: the\n // request was valid, the store was not reachable.\n return {\n status: 500,\n body: problemOf(new Internal()),\n };\n }\n },\n\n // The same production pipeline as `list`: the protocol's parser and its\n // allowlist, the use case, and the Mongo counter over the fake driver.\n facets: async search => {\n let queries;\n try {\n queries = parseFacetQueryParams(entityConstructor, search);\n } catch (error) {\n return {\n status: 400,\n body: problemOf(\n new InvalidQuery({ reason: (error as Error).message }),\n ),\n };\n }\n\n try {\n const counts = await run(\n facetCountsUCFactory(queries).pipe(\n Effect.provideService(EntityFacetCounterTag, counter),\n ),\n );\n return {\n status: 200,\n body: makeEntityFacetsEnvelope(entityConstructor, counts),\n };\n } catch (error) {\n return {\n status: 500,\n body: problemOf(new Internal()),\n };\n }\n },\n\n get: async id => {\n const entity = await run(\n getUCFactory<TEntity>().pipe(\n Effect.provideService(EntityRepositoryTag, repository),\n Effect.provideService(EntityIdTag, id),\n Effect.option,\n ),\n );\n\n return entity._tag === 'None'\n ? { status: 404, body: problemOf(new NotFound({ entity: key })) }\n : {\n status: 200,\n body: makeEntityEnvelope(\n entityConstructor,\n entity.value,\n entityLinks(key, id),\n ),\n };\n },\n\n seed: rows => {\n db.seed(\n key,\n rows.map(row => ({ ...row })),\n );\n },\n\n rows: () => db.read(key),\n\n db,\n };\n};\n"],"names":["EntityFacetCounterTag","EntityIdTag","EntityLoadRequestTag","EntityRepositoryTag","facetCountsUCFactory","getUCFactory","loadUCFactory","envelopeEntityName","Internal","InvalidQuery","makeEntityEnvelope","makeEntityFacetsEnvelope","makeEntityPageEnvelope","NotFound","parseFacetQueryParams","parseLoadRequestParams","problemOf","makeMongoFacetCounter","makeMongoRepository","makeFakeMongoDb","Effect","collectionLinks","key","rel","href","method","entityLinks","id","String","makeEntityBackend","entityConstructor","seed","db","map","row","repository","counter","run","effect","runPromise","list","search","request","error","status","body","reason","message","page","pipe","provideService","facets","queries","counts","get","entity","option","_tag","value","rows","read"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entity-handlers.d.ts","sourceRoot":"","sources":["../../src/fixtures/entity-handlers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,KAAK,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"entity-handlers.d.ts","sourceRoot":"","sources":["../../src/fixtures/entity-handlers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,KAAK,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAE/D,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAE9D,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,oBAAoB,EAE1B,MAAM,qBAAqB,CAAC;AAE7B,MAAM,WAAW,2BAA4B,SAAQ,oBAAoB;IACvE,+EAA+E;IAC/E,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,GAAI,OAAO,SAAS,MAAM,EAC1D,mBAAmB,iBAAiB,CAAC,OAAO,CAAC,EAC7C,yBAAyB,2BAA2B,KACnD;IAAE,QAAQ,EAAE,cAAc,EAAE,CAAC;IAAC,OAAO,EAAE,aAAa,CAAA;CA6BtD,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,GAC/B,KAAK,MAAM,EACX,eAAe,kBAAkB,KAChC,cAAuE,CAAC;AAE3E,YAAY,EAAE,cAAc,EAAE,MAAM,KAAK,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,KAAK,CAAC"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
1
2
|
import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
|
|
3
|
+
import { PROBLEM_CONTENT_TYPE } from '@entifix/core';
|
|
2
4
|
import { http, HttpResponse } from 'msw';
|
|
3
5
|
import { makeEntityBackend } from './entity-backend.js';
|
|
4
6
|
/**
|
|
@@ -13,11 +15,16 @@ import { makeEntityBackend } from './entity-backend.js';
|
|
|
13
15
|
"baseUrl"
|
|
14
16
|
]);
|
|
15
17
|
const backend = makeEntityBackend(entityConstructor, options);
|
|
16
|
-
// Every body is an envelope or
|
|
17
|
-
// the
|
|
18
|
-
|
|
18
|
+
// Every body is an envelope or a problem — JSON either way, and a failure
|
|
19
|
+
// carries the problem content type a service answers with. The cast is the
|
|
20
|
+
// one place the backend's transport-free `unknown` meets msw's body type.
|
|
21
|
+
const respond = ({ status, body })=>HttpResponse.json(body, _extends({
|
|
19
22
|
status
|
|
20
|
-
}
|
|
23
|
+
}, status >= 400 ? {
|
|
24
|
+
headers: {
|
|
25
|
+
'content-type': PROBLEM_CONTENT_TYPE
|
|
26
|
+
}
|
|
27
|
+
} : {}));
|
|
21
28
|
return {
|
|
22
29
|
backend,
|
|
23
30
|
handlers: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/fixtures/entity-handlers.ts"],"sourcesContent":["import type { ConfigurationPlain } from '@entifix/core';\nimport type { Entity, EntityConstructor } from '@entifix/core';\nimport { http, HttpResponse, type RequestHandler } from 'msw';\n\nimport {\n type BackendResponse,\n type EntityBackend,\n type EntityBackendOptions,\n makeEntityBackend,\n} from './entity-backend.js';\n\nexport interface EntityBackendHandlerOptions extends EntityBackendOptions {\n /** The collection endpoint, e.g. `http://localhost:3101/api/product-brand`. */\n baseUrl: string;\n}\n\n/**\n * Puts an {@link makeEntityBackend} behind msw handlers, so a browser under\n * Playwright talks to the real query pipeline over the real wire format.\n *\n * The backend is returned alongside the handlers because a spec usually wants\n * both: the handlers to install, and the backend to reseed or to break with\n * `backend.db.failWith(...)`.\n */\nexport const entityBackendHandlers = <TEntity extends Entity>(\n entityConstructor: EntityConstructor<TEntity>,\n { baseUrl, ...options }: EntityBackendHandlerOptions,\n): { handlers: RequestHandler[]; backend: EntityBackend } => {\n const backend = makeEntityBackend(entityConstructor, options);\n\n // Every body is an envelope or
|
|
1
|
+
{"version":3,"sources":["../../src/fixtures/entity-handlers.ts"],"sourcesContent":["import type { ConfigurationPlain } from '@entifix/core';\nimport type { Entity, EntityConstructor } from '@entifix/core';\nimport { PROBLEM_CONTENT_TYPE } from '@entifix/core';\nimport { http, HttpResponse, type RequestHandler } from 'msw';\n\nimport {\n type BackendResponse,\n type EntityBackend,\n type EntityBackendOptions,\n makeEntityBackend,\n} from './entity-backend.js';\n\nexport interface EntityBackendHandlerOptions extends EntityBackendOptions {\n /** The collection endpoint, e.g. `http://localhost:3101/api/product-brand`. */\n baseUrl: string;\n}\n\n/**\n * Puts an {@link makeEntityBackend} behind msw handlers, so a browser under\n * Playwright talks to the real query pipeline over the real wire format.\n *\n * The backend is returned alongside the handlers because a spec usually wants\n * both: the handlers to install, and the backend to reseed or to break with\n * `backend.db.failWith(...)`.\n */\nexport const entityBackendHandlers = <TEntity extends Entity>(\n entityConstructor: EntityConstructor<TEntity>,\n { baseUrl, ...options }: EntityBackendHandlerOptions,\n): { handlers: RequestHandler[]; backend: EntityBackend } => {\n const backend = makeEntityBackend(entityConstructor, options);\n\n // Every body is an envelope or a problem — JSON either way, and a failure\n // carries the problem content type a service answers with. The cast is the\n // one place the backend's transport-free `unknown` meets msw's body type.\n const respond = ({ status, body }: BackendResponse) =>\n HttpResponse.json(body as Record<string, unknown>, {\n status,\n ...(status >= 400\n ? { headers: { 'content-type': PROBLEM_CONTENT_TYPE } }\n : {}),\n });\n\n return {\n backend,\n handlers: [\n http.get(baseUrl, async ({ request }) =>\n respond(await backend.list(new URL(request.url).searchParams)),\n ),\n // Before `/:id`, which would otherwise take `$facets` for an id.\n http.get(`${baseUrl}/$facets`, async ({ request }) =>\n respond(await backend.facets(new URL(request.url).searchParams)),\n ),\n http.get(`${baseUrl}/:id`, async ({ params }) =>\n respond(await backend.get(String(params['id']))),\n ),\n ],\n };\n};\n\n/**\n * The configuration lookup every entifix frontend makes before it can issue a\n * single entity request: the REST adapters resolve their base URL through it.\n *\n * Stubbing the entity endpoint without this one leaves the page waiting\n * forever and the spec passing vacuously, so it is a first-class fixture rather\n * than something each suite remembers to add.\n */\nexport const configurationHandler = (\n url: string,\n configuration: ConfigurationPlain,\n): RequestHandler => http.get(url, () => HttpResponse.json(configuration));\n\nexport type { RequestHandler } from 'msw';\nexport { http, HttpResponse } from 'msw';\n"],"names":["PROBLEM_CONTENT_TYPE","http","HttpResponse","makeEntityBackend","entityBackendHandlers","entityConstructor","baseUrl","options","backend","respond","status","body","json","headers","handlers","get","request","list","URL","url","searchParams","facets","params","String","configurationHandler","configuration"],"mappings":";;AAEA,SAASA,oBAAoB,QAAQ,gBAAgB;AACrD,SAASC,IAAI,EAAEC,YAAY,QAA6B,MAAM;AAE9D,SAIEC,iBAAiB,QACZ,sBAAsB;AAO7B;;;;;;;CAOC,GACD,OAAO,MAAMC,wBAAwB,CACnCC;QACA,EAAEC,OAAO,EAA2C,OAAtCC;;;IAEd,MAAMC,UAAUL,kBAAkBE,mBAAmBE;IAErD,0EAA0E;IAC1E,2EAA2E;IAC3E,0EAA0E;IAC1E,MAAME,UAAU,CAAC,EAAEC,MAAM,EAAEC,IAAI,EAAmB,GAChDT,aAAaU,IAAI,CAACD,MAAiC;YACjDD;WACIA,UAAU,MACV;YAAEG,SAAS;gBAAE,gBAAgBb;YAAqB;QAAE,IACpD,CAAC;IAGT,OAAO;QACLQ;QACAM,UAAU;YACRb,KAAKc,GAAG,CAACT,SAAS,OAAO,EAAEU,OAAO,EAAE,GAClCP,QAAQ,MAAMD,QAAQS,IAAI,CAAC,IAAIC,IAAIF,QAAQG,GAAG,EAAEC,YAAY;YAE9D,iEAAiE;YACjEnB,KAAKc,GAAG,CAAC,GAAGT,QAAQ,QAAQ,CAAC,EAAE,OAAO,EAAEU,OAAO,EAAE,GAC/CP,QAAQ,MAAMD,QAAQa,MAAM,CAAC,IAAIH,IAAIF,QAAQG,GAAG,EAAEC,YAAY;YAEhEnB,KAAKc,GAAG,CAAC,GAAGT,QAAQ,IAAI,CAAC,EAAE,OAAO,EAAEgB,MAAM,EAAE,GAC1Cb,QAAQ,MAAMD,QAAQO,GAAG,CAACQ,OAAOD,MAAM,CAAC,KAAK;SAEhD;IACH;AACF,EAAE;AAEF;;;;;;;CAOC,GACD,OAAO,MAAME,uBAAuB,CAClCL,KACAM,gBACmBxB,KAAKc,GAAG,CAACI,KAAK,IAAMjB,aAAaU,IAAI,CAACa,gBAAgB;AAG3E,SAASxB,IAAI,EAAEC,YAAY,QAAQ,MAAM"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@entifix/testing-e2e",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "End-to-end testing with one set of journeys and two profiles: mocked backends by default, real infrastructure on demand.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -67,22 +67,22 @@
|
|
|
67
67
|
},
|
|
68
68
|
"dependencies": {
|
|
69
69
|
"@swc/helpers": "0.5.23",
|
|
70
|
-
"@entifix/business": "0.
|
|
71
|
-
"@entifix/
|
|
72
|
-
"@entifix/
|
|
70
|
+
"@entifix/business": "0.10.0",
|
|
71
|
+
"@entifix/core": "0.10.0",
|
|
72
|
+
"@entifix/testing-unit": "0.10.0"
|
|
73
73
|
},
|
|
74
74
|
"peerDependencies": {
|
|
75
75
|
"@nx/devkit": ">=23 <24",
|
|
76
76
|
"@nx/playwright": ">=23 <24",
|
|
77
77
|
"@playwright/test": "*",
|
|
78
78
|
"axios": "*",
|
|
79
|
-
"effect": "^4.0.
|
|
79
|
+
"effect": "^4.0.6",
|
|
80
80
|
"msw": ">=3",
|
|
81
81
|
"@msw/playwright": ">=0.7",
|
|
82
82
|
"vitest": "*",
|
|
83
|
-
"@entifix/
|
|
84
|
-
"@entifix/
|
|
85
|
-
"@entifix/
|
|
83
|
+
"@entifix/amqp": "0.10.0",
|
|
84
|
+
"@entifix/mongo": "0.10.0",
|
|
85
|
+
"@entifix/redis": "0.10.0"
|
|
86
86
|
},
|
|
87
87
|
"peerDependenciesMeta": {
|
|
88
88
|
"@msw/playwright": {
|
|
@@ -119,9 +119,9 @@
|
|
|
119
119
|
"devDependencies": {
|
|
120
120
|
"@nx/devkit": "23.3.0",
|
|
121
121
|
"@nx/playwright": "23.3.0",
|
|
122
|
-
"effect": "4.0.
|
|
123
|
-
"@entifix/
|
|
124
|
-
"@entifix/
|
|
125
|
-
"@entifix/redis": "0.
|
|
122
|
+
"effect": "4.0.6",
|
|
123
|
+
"@entifix/amqp": "0.10.0",
|
|
124
|
+
"@entifix/mongo": "0.10.0",
|
|
125
|
+
"@entifix/redis": "0.10.0"
|
|
126
126
|
}
|
|
127
127
|
}
|