json-rest-api 1.0.29 → 2.0.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/LICENSE +10 -670
- package/LICENSE-GPL-3.0 +674 -0
- package/LICENSE-MIT +21 -0
- package/README.md +39 -30
- package/docs/API.md +744 -1273
- package/docs/GUIDE/01-getting-started.md +338 -0
- package/docs/GUIDE/02-resources-and-relationships.md +33 -0
- package/docs/GUIDE/03-running-example.md +87 -0
- package/docs/GUIDE/04-creating-and-querying.md +181 -0
- package/docs/GUIDE/05-belongs-to.md +177 -0
- package/docs/GUIDE/06-has-many.md +184 -0
- package/docs/GUIDE/07-polymorphic-relationships.md +191 -0
- package/docs/GUIDE/08-many-to-many.md +184 -0
- package/docs/GUIDE/09-pagination-and-sorting.md +149 -0
- package/docs/GUIDE/10-put-and-patch.md +174 -0
- package/docs/GUIDE/11-relationship-endpoints.md +174 -0
- package/docs/GUIDE/12-field-transformations.md +287 -0
- package/docs/GUIDE/13-hooks-and-lifecycle.md +479 -0
- package/docs/GUIDE/14-custom-resource-methods.md +125 -0
- package/docs/GUIDE/15-query-projections.md +266 -0
- package/docs/GUIDE/{GUIDE_X_Autofiltering.md → 16-autofiltering.md} +77 -15
- package/docs/GUIDE/{GUIDE_X_Row_Policies.md → 17-row-policies.md} +137 -44
- package/docs/GUIDE/18-labels.md +86 -0
- package/docs/GUIDE/19-managed-transactions.md +179 -0
- package/docs/GUIDE/20-transaction-outcomes.md +207 -0
- package/docs/GUIDE/21-schema-and-migrations.md +634 -0
- package/docs/GUIDE/22-version-field-migrations.md +208 -0
- package/docs/GUIDE/23-fastify.md +179 -0
- package/docs/GUIDE/24-cors.md +172 -0
- package/docs/GUIDE/{GUIDE_X_URL_Management.md → 25-url-management.md} +7 -1
- package/docs/GUIDE/26-file-uploads.md +278 -0
- package/docs/GUIDE/27-bulk-operations.md +277 -0
- package/docs/GUIDE/28-socketio.md +325 -0
- package/docs/GUIDE/29-writing-plugins.md +278 -0
- package/docs/GUIDE/30-backend-capabilities.md +100 -0
- package/docs/GUIDE/31-positioning.md +181 -0
- package/docs/GUIDE/{GUIDE_Y_Appendices.md → 32-date-and-time.md} +74 -30
- package/docs/GUIDE/33-migrating-to-v2.md +3827 -0
- package/docs/GUIDE/index.md +51 -59
- package/docs/QUICKSTART.md +120 -287
- package/docs/architecture.md +75 -0
- package/docs/contributing.md +178 -0
- package/index.d.ts +36 -0
- package/index.js +1 -22
- package/lib/enhanced-logger.js +91 -85
- package/lib/error-context.js +445 -5
- package/lib/error-formatter.js +219 -59
- package/lib/knex-transaction.js +64 -0
- package/lib/logger-types.d.ts +22 -0
- package/lib/missing-package.js +4 -0
- package/lib/rest-api-errors.js +103 -8
- package/lib/runtime/json-rest-api.js +172 -0
- package/lib/transaction-types.d.ts +59 -0
- package/package.json +97 -27
- package/plugins/core/bulk-operations-plugin.js +191 -184
- package/plugins/core/connectors/express-plugin.js +148 -219
- package/plugins/core/connectors/fastify-plugin.js +125 -82
- package/plugins/core/connectors/lib/busboy-detector.js +74 -156
- package/plugins/core/connectors/lib/connector-core.js +144 -20
- package/plugins/core/connectors/lib/formidable-detector.js +63 -120
- package/plugins/core/connectors/lib/http-validators.js +77 -0
- package/plugins/core/connectors/lib/multipart-helpers.js +18 -0
- package/plugins/core/connectors/lib/request-helpers.js +10 -1
- package/plugins/core/connectors/lib/transport-http-helpers.js +89 -8
- package/plugins/core/connectors/lib/transport-route-schemas.js +7 -4
- package/plugins/core/file-handling-plugin.js +87 -177
- package/plugins/core/lib/anyapi/anyapi-registry.js +213 -164
- package/plugins/core/lib/anyapi/canonical-link-store.js +507 -0
- package/plugins/core/lib/anyapi/canonical-relationship-reader.js +598 -0
- package/plugins/core/lib/anyapi/schema-utils.js +25 -16
- package/plugins/core/lib/anyapi/utils/descriptor-helpers.js +0 -64
- package/plugins/core/lib/dbIntrospection.js +228 -21
- package/plugins/core/lib/dbTablesOperations.js +409 -92
- package/plugins/core/lib/fractional-positioning.js +12 -48
- package/plugins/core/lib/querying/identifier-query.js +19 -0
- package/plugins/core/lib/querying/include-query-helpers.js +364 -0
- package/plugins/core/lib/querying/include-to-many.js +428 -0
- package/plugins/core/lib/querying/include-to-one.js +579 -0
- package/plugins/core/lib/querying/knex-cross-table-search.js +31 -307
- package/plugins/core/lib/querying/knex-json-api-transformers-querying.js +99 -401
- package/plugins/core/lib/querying/knex-pagination-helpers.js +48 -317
- package/plugins/core/lib/querying/knex-process-includes.js +5 -110
- package/plugins/core/lib/querying/knex-query-helpers-base.js +21 -56
- package/plugins/core/lib/querying/knex-query-helpers.js +298 -448
- package/plugins/core/lib/querying/knex-relationship-includes.js +120 -2138
- package/plugins/core/lib/querying/knex-window-queries.js +62 -253
- package/plugins/core/lib/querying/query-builder-utils.js +44 -4
- package/plugins/core/lib/querying/query-constraint.d.ts +12 -0
- package/plugins/core/lib/querying/query-constraint.js +27 -0
- package/plugins/core/lib/querying/query-field-sort-helpers.js +134 -37
- package/plugins/core/lib/querying/relationship-identifiers.js +208 -0
- package/plugins/core/lib/querying/sort-helpers.js +13 -1
- package/plugins/core/lib/querying/storage-adapter-utils.js +13 -5
- package/plugins/core/lib/querying/url-helpers.js +11 -4
- package/plugins/core/lib/querying-writing/compile-schemas.js +148 -249
- package/plugins/core/lib/querying-writing/connectors-query-parser.js +33 -118
- package/plugins/core/lib/querying-writing/database-capabilities.js +149 -223
- package/plugins/core/lib/querying-writing/database-value-normalizers.js +179 -194
- package/plugins/core/lib/querying-writing/default-data-helpers.js +15 -45
- package/plugins/core/lib/querying-writing/field-selection-types.d.ts +43 -0
- package/plugins/core/lib/querying-writing/field-utils.js +113 -92
- package/plugins/core/lib/querying-writing/knex-constants.d.ts +18 -0
- package/plugins/core/lib/querying-writing/knex-constants.js +2 -26
- package/plugins/core/lib/querying-writing/knex-field-helpers.js +100 -290
- package/plugins/core/lib/querying-writing/knex-json-api-transformers.js +31 -120
- package/plugins/core/lib/querying-writing/query-field-helpers.js +108 -32
- package/plugins/core/lib/querying-writing/query-field-types.d.ts +60 -0
- package/plugins/core/lib/querying-writing/relationship-contracts.js +33 -13
- package/plugins/core/lib/querying-writing/request-contracts.js +93 -38
- package/plugins/core/lib/querying-writing/resource-id-normalization.js +23 -5
- package/plugins/core/lib/querying-writing/response-options.js +35 -0
- package/plugins/core/lib/querying-writing/schema-helpers.js +203 -324
- package/plugins/core/lib/querying-writing/scope-validations.js +92 -290
- package/plugins/core/lib/querying-writing/simplified-helpers.js +113 -712
- package/plugins/core/lib/storage/canonical-data-helpers.js +683 -0
- package/plugins/core/lib/storage/canonical-storage-mapping.js +51 -20
- package/plugins/core/lib/storage/ordinary-data-helpers.js +710 -0
- package/plugins/core/lib/storage/storage-adapter.js +128 -62
- package/plugins/core/lib/storage/storage-mapping.js +78 -28
- package/plugins/core/lib/storage/storage-types.d.ts +502 -0
- package/plugins/core/lib/writing/many-to-many-manipulations.js +114 -284
- package/plugins/core/lib/writing/relationship-processor.js +94 -158
- package/plugins/core/lib/writing/resource-version.js +172 -0
- package/plugins/core/lib/writing/reverse-relationship-manipulations.js +110 -0
- package/plugins/core/rest-api-anyapi-knex-plugin.js +116 -2485
- package/plugins/core/rest-api-autofilter-plugin.js +17 -19
- package/plugins/core/rest-api-cors-plugin.js +52 -205
- package/plugins/core/rest-api-knex-plugin.js +45 -1077
- package/plugins/core/rest-api-label-plugin.js +25 -38
- package/plugins/core/rest-api-plugin-hooks/register-relationship-routes.js +5 -5
- package/plugins/core/rest-api-plugin-hooks/register-scope-routes.js +9 -6
- package/plugins/core/rest-api-plugin-hooks/turn-scope-init-into-vars.js +7 -26
- package/plugins/core/rest-api-plugin-hooks/validate-include-configurations.js +20 -26
- package/plugins/core/rest-api-plugin-methods/add-route.js +4 -6
- package/plugins/core/rest-api-plugin-methods/apply-query-filters.js +42 -13
- package/plugins/core/rest-api-plugin-methods/check-permissions.js +11 -5
- package/plugins/core/rest-api-plugin-methods/common.js +291 -395
- package/plugins/core/rest-api-plugin-methods/delete-relationship.js +49 -47
- package/plugins/core/rest-api-plugin-methods/delete.js +31 -25
- package/plugins/core/rest-api-plugin-methods/enrich-attributes.js +108 -148
- package/plugins/core/rest-api-plugin-methods/get-related.js +113 -305
- package/plugins/core/rest-api-plugin-methods/get-relationship.js +25 -18
- package/plugins/core/rest-api-plugin-methods/get.js +36 -68
- package/plugins/core/rest-api-plugin-methods/lifecycle-types.d.ts +225 -0
- package/plugins/core/rest-api-plugin-methods/patch-relationship.js +28 -25
- package/plugins/core/rest-api-plugin-methods/patch.js +46 -99
- package/plugins/core/rest-api-plugin-methods/post-relationship.js +49 -53
- package/plugins/core/rest-api-plugin-methods/post.js +51 -51
- package/plugins/core/rest-api-plugin-methods/put.js +69 -148
- package/plugins/core/rest-api-plugin-methods/query.js +37 -81
- package/plugins/core/rest-api-plugin-methods/release.js +2 -1
- package/plugins/core/rest-api-plugin.js +32 -46
- package/plugins/core/rest-api-positioning-plugin.js +183 -628
- package/plugins/core/rest-api-query-projections-plugin.js +19 -102
- package/plugins/core/rest-api-row-policy-plugin.js +3 -3
- package/plugins/core/socketio-plugin.js +364 -344
- package/plugins/storage/local-storage.js +40 -36
- package/types/autofilter.d.ts +57 -0
- package/types/bulk-methods.d.ts +63 -0
- package/types/errors.d.ts +118 -0
- package/types/fastify-options.d.ts +19 -0
- package/types/file-detectors.d.ts +33 -0
- package/types/file-storage.d.ts +48 -0
- package/types/hook-context.d.ts +180 -0
- package/types/plugin-options.d.ts +53 -0
- package/types/relationship-methods.d.ts +74 -0
- package/types/representations.d.ts +50 -0
- package/types/resource-methods.d.ts +95 -0
- package/types/resource-schema.d.ts +157 -0
- package/types/row-policy.d.ts +31 -0
- package/types/runtime.d.ts +132 -0
- package/types/transactions.d.ts +21 -0
- package/.claude/agents/library-guide-expert.md +0 -30
- package/.claude/agents/rest-api-internals-expert.md +0 -54
- package/.claude/settings.local.json +0 -70
- package/AGENTS.md +0 -34
- package/CLAUDE.md +0 -160
- package/CRUSH.md +0 -55
- package/JSKIT_BACKEND_MIGRATION_TRACKER.txt +0 -180
- package/SINGLE_VALIDATION_CONTRACT_TODO.txt +0 -172
- package/TODO.todo +0 -13
- package/connectors_ideas/fastify.js +0 -217
- package/connectors_ideas/koa-plugin.js +0 -112
- package/docs/.bundle/config +0 -2
- package/docs/COMPARISON.md +0 -433
- package/docs/GUIDE/GUIDE_1_Initial_Setup.md +0 -1057
- package/docs/GUIDE/GUIDE_2_1_The_Starting_Point.md +0 -88
- package/docs/GUIDE/GUIDE_2_2_Manipulating_And_Searching_Tables.md +0 -808
- package/docs/GUIDE/GUIDE_2_3_BelongsTo_Relationships.md +0 -491
- package/docs/GUIDE/GUIDE_2_4_HasMany_Records.md +0 -398
- package/docs/GUIDE/GUIDE_2_5_HasMany_Polymorphic.md +0 -898
- package/docs/GUIDE/GUIDE_2_6_Many_To_Many.md +0 -712
- package/docs/GUIDE/GUIDE_2_7_Pagination_And_Ordering.md +0 -1247
- package/docs/GUIDE/GUIDE_2_8_Effects_of_PUT_and_PATCH.md +0 -748
- package/docs/GUIDE/GUIDE_2_9_Relationships_Urls.md +0 -517
- package/docs/GUIDE/GUIDE_2_Data_And_Relations.md +0 -66
- package/docs/GUIDE/GUIDE_3_Field_Transformations.md +0 -1252
- package/docs/GUIDE/GUIDE_5_Non-Db_Resources.md +0 -1107
- package/docs/GUIDE/GUIDE_6_Positioning.md +0 -692
- package/docs/GUIDE/GUIDE_7_Hooks_Data_Management_And_Plugins.md +0 -1491
- package/docs/GUIDE/GUIDE_X_Bulk_Operations.md +0 -732
- package/docs/GUIDE/GUIDE_X_Cors.md +0 -1957
- package/docs/GUIDE/GUIDE_X_Fastify.md +0 -78
- package/docs/GUIDE/GUIDE_X_File_Uploads.md +0 -729
- package/docs/GUIDE/GUIDE_X_Knex_Schema_And_Migrations.md +0 -370
- package/docs/GUIDE/GUIDE_X_Query_Projections.md +0 -159
- package/docs/GUIDE/GUIDE_X_SocketIO.md +0 -1040
- package/docs/GUIDE/GUIDE_X_Writing_Plugins.md +0 -201
- package/docs/Gemfile +0 -6
- package/docs/Gemfile.lock +0 -308
- package/docs/ONBOARDING.md +0 -315
- package/docs/_config.yml +0 -36
- package/docs/_layouts/default.html +0 -123
- package/docs/apple-touch-icon.svg +0 -4
- package/docs/assets/css/style.scss +0 -392
- package/docs/favicon.svg +0 -4
- package/docs/index.md +0 -164
- package/docs/mini-guides/file-uploads-complete.md +0 -161
- package/eslint.config.js +0 -13
- package/examples/url-override-example.js +0 -137
- package/fixing_plan.md +0 -112
- package/plugins/core/lib/anyapi/query/anyapi-query-adapter.js +0 -657
- package/plugins/core/lib/querying-writing/return-record-settings.js +0 -47
- package/plugins/core/lib/writing/knex-json-api-transformers-writing.js +0 -110
- package/plugins/storage/s3-storage.js +0 -93
- package/quickTest.js +0 -136
- package/scripts/debug-anyapi-review-filter.mjs +0 -63
- package/scripts/inspect-anyapi-descriptor-country.mjs +0 -19
- package/scripts/inspect-anyapi-descriptor.mjs +0 -19
- package/scripts/run-docs.js +0 -133
- package/test-debug.js +0 -59
- package/tests/README.md +0 -202
- package/tests/TEST_TEMPLATE.test.js +0 -178
- package/tests/anyapi-basic.test.js +0 -105
- package/tests/anyapi-cursor-pagination.test.js +0 -148
- package/tests/anyapi-custom-idproperty.test.js +0 -163
- package/tests/autofilter.test.js +0 -463
- package/tests/bulk-operations.test.js +0 -657
- package/tests/computed-fields.test.js +0 -586
- package/tests/cors.test.js +0 -834
- package/tests/curl.test.js +0 -467
- package/tests/custom-id-mysql-returning-fallback.test.js +0 -128
- package/tests/custom-id-simplified-post.test.js +0 -75
- package/tests/custom-idproperty-relationships.test.js +0 -932
- package/tests/db-introspection.test.js +0 -521
- package/tests/db-table-operations.test.js +0 -798
- package/tests/fastify-plugin.test.js +0 -184
- package/tests/field-getters.test.js +0 -370
- package/tests/field-setters.test.js +0 -306
- package/tests/file-handling.test.js +0 -155
- package/tests/fixtures/api-configs.js +0 -2566
- package/tests/full-jsonapi-belongsto-linkage.test.js +0 -150
- package/tests/helpers/fake-fastify.js +0 -99
- package/tests/helpers/storage-mode.js +0 -65
- package/tests/helpers/test-utils.js +0 -203
- package/tests/http-connectors-parity.test.js +0 -395
- package/tests/id-normalization.test.js +0 -444
- package/tests/include-depth-validation.test.js +0 -331
- package/tests/includes.test.js +0 -427
- package/tests/local-storage.test.js +0 -96
- package/tests/logical-id-write-validation.test.js +0 -151
- package/tests/nested-includes.test.js +0 -617
- package/tests/pagination-boundaries.test.js +0 -154
- package/tests/pagination-contract.test.js +0 -122
- package/tests/pagination-cursor-multifield.test.js +0 -641
- package/tests/pagination-enhanced.test.js +0 -563
- package/tests/polymorphic-relationships.test.js +0 -347
- package/tests/polymorphic-simple.test.js +0 -148
- package/tests/positioning-advanced.test.js +0 -692
- package/tests/positioning-extended.test.js +0 -915
- package/tests/positioning-multifilter.test.js +0 -699
- package/tests/positioning.test.js +0 -560
- package/tests/post-commit-hooks.test.js +0 -120
- package/tests/projected-fields.test.js +0 -319
- package/tests/public-exports.test.js +0 -15
- package/tests/put-create-parity.test.js +0 -216
- package/tests/queries.test.js +0 -521
- package/tests/query-limits.test.js +0 -584
- package/tests/relationship-endpoints.test.js +0 -620
- package/tests/relationship-include-storage-adapter.test.js +0 -56
- package/tests/relationships.test.js +0 -681
- package/tests/rest-api.test.js +0 -337
- package/tests/return-record-settings.test.js +0 -184
- package/tests/row-policy.test.js +0 -489
- package/tests/s3-storage.test.js +0 -38
- package/tests/searchschema-knex-behavior.test.js +0 -187
- package/tests/searchschema-merge.test.js +0 -151
- package/tests/socketio.test.js +0 -860
- package/tests/storage-mapping.test.js +0 -362
- package/tests/temporal-boundaries.test.js +0 -208
- package/tests/test-development-guide.md +0 -370
- package/tests/virtual-fields.test.js +0 -404
|
@@ -1,370 +0,0 @@
|
|
|
1
|
-
# Test Development Guide for JSON-REST-API
|
|
2
|
-
|
|
3
|
-
## Missing tests:
|
|
4
|
-
|
|
5
|
-
⎿ ☒ Plan test structure and API configurations
|
|
6
|
-
X Create test file with basic setup and utilities
|
|
7
|
-
X Implement basic CRUD tests (POST, GET, PUT, PATCH, DELETE)
|
|
8
|
-
? Implement relationship tests (belongsTo, hasMany, many-to-many)
|
|
9
|
-
? Implement query tests (filtering, sorting, pagination)
|
|
10
|
-
? Implement include/sideloading tests
|
|
11
|
-
? Implement sparse fieldsets tests
|
|
12
|
-
? Implement transaction and error handling tests
|
|
13
|
-
|
|
14
|
-
This guide provides comprehensive instructions for continuing test development following established patterns.
|
|
15
|
-
|
|
16
|
-
## Critical Requirements
|
|
17
|
-
|
|
18
|
-
### 1. Strict Mode is MANDATORY
|
|
19
|
-
|
|
20
|
-
**NEVER** use `simplified: true` in tests (except internally for pivot operations):
|
|
21
|
-
|
|
22
|
-
```javascript
|
|
23
|
-
// ✅ CORRECT - Always use simplified: false
|
|
24
|
-
const result = await api.resources.books.post({
|
|
25
|
-
inputRecord: bookDoc,
|
|
26
|
-
simplified: false // REQUIRED
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
// ❌ WRONG - Never use simplified: true in tests
|
|
30
|
-
const result = await api.resources.books.post({
|
|
31
|
-
inputRecord: bookDoc,
|
|
32
|
-
simplified: true // FORBIDDEN in tests
|
|
33
|
-
});
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
### 2. Foreign Keys via Relationships ONLY
|
|
37
|
-
|
|
38
|
-
In strict mode, foreign keys MUST be set through relationships:
|
|
39
|
-
|
|
40
|
-
```javascript
|
|
41
|
-
// ❌ WRONG - Foreign key in attributes
|
|
42
|
-
const bookDoc = createJsonApiDocument('books', {
|
|
43
|
-
title: 'My Book',
|
|
44
|
-
country_id: 123, // WILL FAIL!
|
|
45
|
-
publisher_id: 456 // WILL FAIL!
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
// ✅ CORRECT - Foreign keys via relationships
|
|
49
|
-
const bookDoc = createJsonApiDocument('books',
|
|
50
|
-
{
|
|
51
|
-
title: 'My Book' // Only non-foreign-key attributes
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
country: createRelationship(resourceIdentifier('countries', countryId)),
|
|
55
|
-
publisher: createRelationship(resourceIdentifier('publishers', publisherId))
|
|
56
|
-
}
|
|
57
|
-
);
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
### 3. returnFullRecord Configuration
|
|
61
|
-
|
|
62
|
-
Control what methods return:
|
|
63
|
-
|
|
64
|
-
```javascript
|
|
65
|
-
// In API configuration
|
|
66
|
-
returnFullRecord: {
|
|
67
|
-
post: 'full', // Return created record (needed to get ID)
|
|
68
|
-
put: 'no', // Don't return after replacement
|
|
69
|
-
patch: 'no' // Don't return after update
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Override per call if needed
|
|
73
|
-
const result = await api.resources.books.put({
|
|
74
|
-
id: bookId,
|
|
75
|
-
inputRecord: putDoc,
|
|
76
|
-
simplified: false,
|
|
77
|
-
returnFullRecord: 'no' // Override to not return
|
|
78
|
-
});
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
### 4. Database Operations Rules
|
|
82
|
-
|
|
83
|
-
**ONLY** these Knex operations are allowed directly:
|
|
84
|
-
|
|
85
|
-
```javascript
|
|
86
|
-
// ✅ ALLOWED - Counting records
|
|
87
|
-
const count = await countRecords(knex, 'basic_books');
|
|
88
|
-
|
|
89
|
-
// ✅ ALLOWED - Cleaning tables between tests
|
|
90
|
-
await cleanTables(knex, ['basic_books', 'basic_authors']);
|
|
91
|
-
|
|
92
|
-
// ❌ FORBIDDEN - Direct queries
|
|
93
|
-
const books = await knex('basic_books').select('*'); // NO!
|
|
94
|
-
|
|
95
|
-
// ❌ FORBIDDEN - Direct inserts
|
|
96
|
-
await knex('basic_books').insert({...}); // NO!
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
All data operations MUST go through the API.
|
|
100
|
-
|
|
101
|
-
## Test Structure Patterns
|
|
102
|
-
|
|
103
|
-
### Basic Test Setup
|
|
104
|
-
|
|
105
|
-
```javascript
|
|
106
|
-
describe('Feature Name', () => {
|
|
107
|
-
let basicApi;
|
|
108
|
-
let extendedApi;
|
|
109
|
-
|
|
110
|
-
before(async () => {
|
|
111
|
-
// Initialize APIs once
|
|
112
|
-
basicApi = await createBasicApi(knex);
|
|
113
|
-
extendedApi = await createExtendedApi(knex);
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
after(async () => {
|
|
117
|
-
// CRITICAL: Close database connection
|
|
118
|
-
await knex.destroy();
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
describe('Sub-feature', () => {
|
|
122
|
-
beforeEach(async () => {
|
|
123
|
-
// Clean tables before EACH test
|
|
124
|
-
await cleanTables(knex, [
|
|
125
|
-
'basic_countries', 'basic_publishers',
|
|
126
|
-
'basic_authors', 'basic_books', 'basic_book_authors'
|
|
127
|
-
]);
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
it('should do something', async () => {
|
|
131
|
-
// Test implementation
|
|
132
|
-
});
|
|
133
|
-
});
|
|
134
|
-
});
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
### Creating Test Data
|
|
138
|
-
|
|
139
|
-
```javascript
|
|
140
|
-
// Step 1: Create parent resources first
|
|
141
|
-
const countryDoc = createJsonApiDocument('countries', {
|
|
142
|
-
name: 'Test Country',
|
|
143
|
-
code: 'TC'
|
|
144
|
-
});
|
|
145
|
-
const countryResult = await basicApi.resources.countries.post({
|
|
146
|
-
inputRecord: countryDoc,
|
|
147
|
-
simplified: false
|
|
148
|
-
});
|
|
149
|
-
const countryId = countryResult.data.id;
|
|
150
|
-
|
|
151
|
-
// Step 2: Create child resources with relationships
|
|
152
|
-
const publisherDoc = createJsonApiDocument('publishers',
|
|
153
|
-
{ name: 'Test Publisher' },
|
|
154
|
-
{
|
|
155
|
-
country: createRelationship(resourceIdentifier('countries', countryId))
|
|
156
|
-
}
|
|
157
|
-
);
|
|
158
|
-
const publisherResult = await basicApi.resources.publishers.post({
|
|
159
|
-
inputRecord: publisherDoc,
|
|
160
|
-
simplified: false
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
// Step 3: Create many-to-many relationships
|
|
164
|
-
const bookDoc = createJsonApiDocument('books',
|
|
165
|
-
{ title: 'Test Book' },
|
|
166
|
-
{
|
|
167
|
-
country: createRelationship(resourceIdentifier('countries', countryId)),
|
|
168
|
-
publisher: createRelationship(resourceIdentifier('publishers', publisherId)),
|
|
169
|
-
authors: createToManyRelationship([
|
|
170
|
-
resourceIdentifier('authors', author1Id),
|
|
171
|
-
resourceIdentifier('authors', author2Id)
|
|
172
|
-
])
|
|
173
|
-
}
|
|
174
|
-
);
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
### Validation Patterns
|
|
178
|
-
|
|
179
|
-
```javascript
|
|
180
|
-
// 1. Always validate JSON:API structure first
|
|
181
|
-
validateJsonApiStructure(result, false); // false = single resource
|
|
182
|
-
validateJsonApiStructure(result, true); // true = collection
|
|
183
|
-
|
|
184
|
-
// 2. Validate attributes
|
|
185
|
-
assertResourceAttributes(result.data, {
|
|
186
|
-
title: 'Expected Title',
|
|
187
|
-
price: '29.99'
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
// 3. Validate relationships
|
|
191
|
-
assertResourceRelationship(result.data, 'publisher',
|
|
192
|
-
resourceIdentifier('publishers', publisherId));
|
|
193
|
-
|
|
194
|
-
// 4. Validate included resources
|
|
195
|
-
assert(result.included, 'Should have included data');
|
|
196
|
-
const publisher = result.included.find(r => r.type === 'publishers');
|
|
197
|
-
assert(publisher, 'Should include publisher');
|
|
198
|
-
|
|
199
|
-
// 5. Count database records for verification
|
|
200
|
-
const count = await countRecords(knex, 'basic_books');
|
|
201
|
-
assert.equal(count, 1, 'Should have created one book');
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
## Common Test Scenarios
|
|
205
|
-
|
|
206
|
-
### 1. Testing Relationships
|
|
207
|
-
|
|
208
|
-
```javascript
|
|
209
|
-
describe('Relationship Operations', () => {
|
|
210
|
-
it('should update many-to-many relationships', async () => {
|
|
211
|
-
// Create initial relationships
|
|
212
|
-
const bookDoc = createJsonApiDocument('books',
|
|
213
|
-
{ title: 'Book with Authors' },
|
|
214
|
-
{
|
|
215
|
-
authors: createToManyRelationship([
|
|
216
|
-
resourceIdentifier('authors', author1Id),
|
|
217
|
-
resourceIdentifier('authors', author2Id)
|
|
218
|
-
])
|
|
219
|
-
}
|
|
220
|
-
);
|
|
221
|
-
|
|
222
|
-
// Update relationships via PATCH
|
|
223
|
-
const patchDoc = {
|
|
224
|
-
data: {
|
|
225
|
-
type: 'books',
|
|
226
|
-
id: String(bookId),
|
|
227
|
-
relationships: {
|
|
228
|
-
authors: createToManyRelationship([
|
|
229
|
-
resourceIdentifier('authors', author2Id), // Keep this
|
|
230
|
-
resourceIdentifier('authors', author3Id) // Add this
|
|
231
|
-
// author1 will be removed
|
|
232
|
-
])
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
};
|
|
236
|
-
|
|
237
|
-
await basicApi.resources.books.patch({
|
|
238
|
-
id: bookId,
|
|
239
|
-
inputRecord: patchDoc,
|
|
240
|
-
simplified: false
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
// Verify pivot table changes
|
|
244
|
-
const pivotCount = await countRecords(knex, 'basic_book_authors');
|
|
245
|
-
assert.equal(pivotCount, 2);
|
|
246
|
-
});
|
|
247
|
-
});
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
### 2. Testing Query Operations
|
|
251
|
-
|
|
252
|
-
```javascript
|
|
253
|
-
describe('Query Operations', () => {
|
|
254
|
-
it('should filter and sort with pagination', async () => {
|
|
255
|
-
const result = await api.resources.books.query({
|
|
256
|
-
queryParams: {
|
|
257
|
-
filters: { language: 'en', price: '19.99' },
|
|
258
|
-
sort: ['title', '-published_date'],
|
|
259
|
-
page: { number: 1, size: 10 },
|
|
260
|
-
include: ['publisher', 'authors']
|
|
261
|
-
},
|
|
262
|
-
simplified: false
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
validateJsonApiStructure(result, true);
|
|
266
|
-
assert(result.data.length <= 10, 'Should respect page size');
|
|
267
|
-
});
|
|
268
|
-
});
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
### 3. Testing Error Conditions
|
|
272
|
-
|
|
273
|
-
```javascript
|
|
274
|
-
describe('Error Handling', () => {
|
|
275
|
-
it('should reject invalid relationships', async () => {
|
|
276
|
-
const bookDoc = createJsonApiDocument('books',
|
|
277
|
-
{ title: 'Invalid Book' },
|
|
278
|
-
{
|
|
279
|
-
publisher: createRelationship(resourceIdentifier('publishers', 99999))
|
|
280
|
-
}
|
|
281
|
-
);
|
|
282
|
-
|
|
283
|
-
await assert.rejects(
|
|
284
|
-
async () => {
|
|
285
|
-
await api.resources.books.post({
|
|
286
|
-
inputRecord: bookDoc,
|
|
287
|
-
simplified: false
|
|
288
|
-
});
|
|
289
|
-
},
|
|
290
|
-
(err) => {
|
|
291
|
-
return err.code === 'REST_API_RESOURCE' &&
|
|
292
|
-
err.subtype === 'not_found';
|
|
293
|
-
},
|
|
294
|
-
'Should throw not found error for invalid publisher'
|
|
295
|
-
);
|
|
296
|
-
});
|
|
297
|
-
});
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
## Schema Configuration for Tests
|
|
301
|
-
|
|
302
|
-
### Enable Filtering
|
|
303
|
-
|
|
304
|
-
Add `search: true` to fields that need filtering:
|
|
305
|
-
|
|
306
|
-
```javascript
|
|
307
|
-
schema: {
|
|
308
|
-
title: { type: 'string', required: true, search: true },
|
|
309
|
-
price: { type: 'decimal', precision: 10, scale: 2, search: true },
|
|
310
|
-
country_id: {
|
|
311
|
-
type: 'number',
|
|
312
|
-
belongsTo: 'countries',
|
|
313
|
-
as: 'country',
|
|
314
|
-
search: true // Enable filtering on foreign key
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
```
|
|
318
|
-
|
|
319
|
-
### Enable Sorting
|
|
320
|
-
|
|
321
|
-
Configure sortable fields in plugin options:
|
|
322
|
-
|
|
323
|
-
```javascript
|
|
324
|
-
await api.use(RestApiPlugin, {
|
|
325
|
-
simplified: false,
|
|
326
|
-
sortableFields: ['id', 'title', 'price', 'published_date'],
|
|
327
|
-
// ... other options
|
|
328
|
-
});
|
|
329
|
-
```
|
|
330
|
-
|
|
331
|
-
## Test Data Best Practices
|
|
332
|
-
|
|
333
|
-
1. **Use descriptive names**: 'Test Book A' instead of 'Book 1'
|
|
334
|
-
2. **Create minimal data**: Only what's needed for the test
|
|
335
|
-
3. **Clean between tests**: Always use `beforeEach` with `cleanTables`
|
|
336
|
-
4. **Store IDs for reuse**: Extract IDs immediately after creation
|
|
337
|
-
5. **Use unique prefixes**: 'basic_' vs 'ext_' for table names
|
|
338
|
-
|
|
339
|
-
## Debugging Tests
|
|
340
|
-
|
|
341
|
-
```bash
|
|
342
|
-
# Run with debug output
|
|
343
|
-
DEBUG=* npm test
|
|
344
|
-
|
|
345
|
-
# Run single test file
|
|
346
|
-
npm test -- tests/relationships.test.js
|
|
347
|
-
|
|
348
|
-
# Check for hanging tests
|
|
349
|
-
# Ensure after() hook closes database: await knex.destroy()
|
|
350
|
-
```
|
|
351
|
-
|
|
352
|
-
## Common Pitfalls to Avoid
|
|
353
|
-
|
|
354
|
-
1. **Forgetting simplified: false** - Will cause validation to fail
|
|
355
|
-
2. **Setting foreign keys in attributes** - Use relationships instead
|
|
356
|
-
3. **Not cleaning between tests** - Causes data conflicts
|
|
357
|
-
4. **Direct database access** - Always use API methods
|
|
358
|
-
5. **Not closing database** - Tests will hang
|
|
359
|
-
6. **Assuming sort order** - Always specify sort explicitly
|
|
360
|
-
7. **Hardcoding IDs** - Always extract from creation responses
|
|
361
|
-
|
|
362
|
-
## Next Test Suites to Implement
|
|
363
|
-
|
|
364
|
-
1. **sparse-fieldsets.test.js** - Field selection tests
|
|
365
|
-
2. **errors.test.js** - Comprehensive error handling
|
|
366
|
-
3. **transactions.test.js** - Transaction rollback tests
|
|
367
|
-
4. **validation.test.js** - Schema validation edge cases
|
|
368
|
-
5. **polymorphic.test.js** - Polymorphic relationship tests
|
|
369
|
-
|
|
370
|
-
Each should follow the patterns established in existing tests.
|