@teleporthq/teleport-plugin-next-data-source 0.43.74 → 0.44.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/__tests__/_helpers/pagination-widget-fixture.ts +95 -5
- package/__tests__/blog-adjacent-arranged.test.ts +176 -0
- package/__tests__/blog-post-contents.test.ts +212 -0
- package/__tests__/blog-post-page-enrichment.test.ts +28 -5
- package/__tests__/blog-post-picture-stand-in.test.ts +48 -0
- package/__tests__/blog-post-reading-time.test.ts +55 -0
- package/__tests__/booking-item-transform.test.ts +120 -0
- package/__tests__/browser-row-policy.test.ts +13 -3
- package/__tests__/content-preset-wiring.test.ts +108 -0
- package/__tests__/fetchers.test.ts +1 -1
- package/__tests__/fixed-list-sort.test.ts +183 -0
- package/__tests__/infinite-scroll.test.ts +154 -5
- package/__tests__/list-sort-order.test.ts +61 -0
- package/__tests__/null-filter-where.test.ts +132 -0
- package/__tests__/pagination-filter-groups.test.ts +186 -0
- package/__tests__/pg-date-parser.test.ts +73 -0
- package/__tests__/plain-list-sort.test.ts +215 -0
- package/__tests__/product-price-sort.ts +58 -25
- package/__tests__/range-control.test.ts +159 -0
- package/__tests__/rest-api-key-header.test.ts +18 -0
- package/__tests__/search-input-marker.test.ts +86 -0
- package/__tests__/search-url-sync.test.ts +61 -16
- package/__tests__/shared-resource-prefetch.test.ts +65 -0
- package/__tests__/table-read-route-protected-tables.test.ts +33 -3
- package/dist/cjs/count-effect.d.ts +7 -1
- package/dist/cjs/count-effect.d.ts.map +1 -1
- package/dist/cjs/count-effect.js +15 -5
- package/dist/cjs/count-effect.js.map +1 -1
- package/dist/cjs/fetchers/pg-client-import.d.ts +12 -0
- package/dist/cjs/fetchers/pg-client-import.d.ts.map +1 -0
- package/dist/cjs/fetchers/pg-client-import.js +15 -0
- package/dist/cjs/fetchers/pg-client-import.js.map +1 -0
- package/dist/cjs/fetchers/postgresql.d.ts.map +1 -1
- package/dist/cjs/fetchers/postgresql.js +4 -1
- package/dist/cjs/fetchers/postgresql.js.map +1 -1
- package/dist/cjs/fetchers/raw-query.d.ts.map +1 -1
- package/dist/cjs/fetchers/raw-query.js +2 -1
- package/dist/cjs/fetchers/raw-query.js.map +1 -1
- package/dist/cjs/fetchers/rest-api.d.ts.map +1 -1
- package/dist/cjs/fetchers/rest-api.js +3 -1
- package/dist/cjs/fetchers/rest-api.js.map +1 -1
- package/dist/cjs/fetchers/teleport.d.ts.map +1 -1
- package/dist/cjs/fetchers/teleport.js +5 -2
- package/dist/cjs/fetchers/teleport.js.map +1 -1
- package/dist/cjs/fetchers/utils/browser-row-policy.d.ts +7 -6
- package/dist/cjs/fetchers/utils/browser-row-policy.d.ts.map +1 -1
- package/dist/cjs/fetchers/utils/browser-row-policy.js +7 -33
- package/dist/cjs/fetchers/utils/browser-row-policy.js.map +1 -1
- package/dist/cjs/filter-utils.d.ts +19 -7
- package/dist/cjs/filter-utils.d.ts.map +1 -1
- package/dist/cjs/filter-utils.js +49 -13
- package/dist/cjs/filter-utils.js.map +1 -1
- package/dist/cjs/infinite-scroll.d.ts +25 -2
- package/dist/cjs/infinite-scroll.d.ts.map +1 -1
- package/dist/cjs/infinite-scroll.js +144 -33
- package/dist/cjs/infinite-scroll.js.map +1 -1
- package/dist/cjs/list-sort-order.d.ts +14 -0
- package/dist/cjs/list-sort-order.d.ts.map +1 -0
- package/dist/cjs/list-sort-order.js +36 -0
- package/dist/cjs/list-sort-order.js.map +1 -0
- package/dist/cjs/pagination-controls.d.ts +22 -3
- package/dist/cjs/pagination-controls.d.ts.map +1 -1
- package/dist/cjs/pagination-controls.js +29 -3
- package/dist/cjs/pagination-controls.js.map +1 -1
- package/dist/cjs/pagination-plugin.d.ts.map +1 -1
- package/dist/cjs/pagination-plugin.js +267 -212
- package/dist/cjs/pagination-plugin.js.map +1 -1
- package/dist/cjs/product-price-sort.d.ts +0 -9
- package/dist/cjs/product-price-sort.d.ts.map +1 -1
- package/dist/cjs/product-price-sort.js +1 -13
- package/dist/cjs/product-price-sort.js.map +1 -1
- package/dist/cjs/range-control.d.ts +45 -0
- package/dist/cjs/range-control.d.ts.map +1 -0
- package/dist/cjs/range-control.js +165 -0
- package/dist/cjs/range-control.js.map +1 -0
- package/dist/cjs/row-order.d.ts +20 -0
- package/dist/cjs/row-order.d.ts.map +1 -0
- package/dist/cjs/row-order.js +46 -0
- package/dist/cjs/row-order.js.map +1 -0
- package/dist/cjs/search-input.d.ts +42 -0
- package/dist/cjs/search-input.d.ts.map +1 -0
- package/dist/cjs/search-input.js +158 -0
- package/dist/cjs/search-input.js.map +1 -0
- package/dist/cjs/sort-utils.d.ts +10 -0
- package/dist/cjs/sort-utils.d.ts.map +1 -1
- package/dist/cjs/sort-utils.js +22 -1
- package/dist/cjs/sort-utils.js.map +1 -1
- package/dist/cjs/transformations/blog-adjacent-posts.d.ts +11 -1
- package/dist/cjs/transformations/blog-adjacent-posts.d.ts.map +1 -1
- package/dist/cjs/transformations/blog-adjacent-posts.js +14 -1
- package/dist/cjs/transformations/blog-adjacent-posts.js.map +1 -1
- package/dist/cjs/transformations/blog-comments.d.ts +1 -1
- package/dist/cjs/transformations/blog-comments.d.ts.map +1 -1
- package/dist/cjs/transformations/blog-comments.js +1 -1
- package/dist/cjs/transformations/blog-comments.js.map +1 -1
- package/dist/cjs/transformations/blog-post.d.ts +14 -0
- package/dist/cjs/transformations/blog-post.d.ts.map +1 -1
- package/dist/cjs/transformations/blog-post.js +4 -1
- package/dist/cjs/transformations/blog-post.js.map +1 -1
- package/dist/cjs/transformations/booking-item.d.ts +24 -0
- package/dist/cjs/transformations/booking-item.d.ts.map +1 -0
- package/dist/cjs/transformations/booking-item.js +27 -0
- package/dist/cjs/transformations/booking-item.js.map +1 -0
- package/dist/cjs/transformations/heading-anchors.d.ts +32 -8
- package/dist/cjs/transformations/heading-anchors.d.ts.map +1 -1
- package/dist/cjs/transformations/heading-anchors.js +34 -10
- package/dist/cjs/transformations/heading-anchors.js.map +1 -1
- package/dist/cjs/transformations/index.d.ts +27 -13
- package/dist/cjs/transformations/index.d.ts.map +1 -1
- package/dist/cjs/transformations/index.js +73 -16
- package/dist/cjs/transformations/index.js.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/cjs/utils.d.ts.map +1 -1
- package/dist/cjs/utils.js +52 -3
- package/dist/cjs/utils.js.map +1 -1
- package/dist/esm/count-effect.d.ts +7 -1
- package/dist/esm/count-effect.d.ts.map +1 -1
- package/dist/esm/count-effect.js +15 -5
- package/dist/esm/count-effect.js.map +1 -1
- package/dist/esm/fetchers/pg-client-import.d.ts +12 -0
- package/dist/esm/fetchers/pg-client-import.d.ts.map +1 -0
- package/dist/esm/fetchers/pg-client-import.js +12 -0
- package/dist/esm/fetchers/pg-client-import.js.map +1 -0
- package/dist/esm/fetchers/postgresql.d.ts.map +1 -1
- package/dist/esm/fetchers/postgresql.js +5 -2
- package/dist/esm/fetchers/postgresql.js.map +1 -1
- package/dist/esm/fetchers/raw-query.d.ts.map +1 -1
- package/dist/esm/fetchers/raw-query.js +2 -1
- package/dist/esm/fetchers/raw-query.js.map +1 -1
- package/dist/esm/fetchers/rest-api.d.ts.map +1 -1
- package/dist/esm/fetchers/rest-api.js +3 -1
- package/dist/esm/fetchers/rest-api.js.map +1 -1
- package/dist/esm/fetchers/teleport.d.ts.map +1 -1
- package/dist/esm/fetchers/teleport.js +6 -3
- package/dist/esm/fetchers/teleport.js.map +1 -1
- package/dist/esm/fetchers/utils/browser-row-policy.d.ts +7 -6
- package/dist/esm/fetchers/utils/browser-row-policy.d.ts.map +1 -1
- package/dist/esm/fetchers/utils/browser-row-policy.js +5 -31
- package/dist/esm/fetchers/utils/browser-row-policy.js.map +1 -1
- package/dist/esm/filter-utils.d.ts +19 -7
- package/dist/esm/filter-utils.d.ts.map +1 -1
- package/dist/esm/filter-utils.js +46 -12
- package/dist/esm/filter-utils.js.map +1 -1
- package/dist/esm/infinite-scroll.d.ts +25 -2
- package/dist/esm/infinite-scroll.d.ts.map +1 -1
- package/dist/esm/infinite-scroll.js +142 -32
- package/dist/esm/infinite-scroll.js.map +1 -1
- package/dist/esm/list-sort-order.d.ts +14 -0
- package/dist/esm/list-sort-order.d.ts.map +1 -0
- package/dist/esm/list-sort-order.js +32 -0
- package/dist/esm/list-sort-order.js.map +1 -0
- package/dist/esm/pagination-controls.d.ts +22 -3
- package/dist/esm/pagination-controls.d.ts.map +1 -1
- package/dist/esm/pagination-controls.js +28 -2
- package/dist/esm/pagination-controls.js.map +1 -1
- package/dist/esm/pagination-plugin.d.ts.map +1 -1
- package/dist/esm/pagination-plugin.js +271 -216
- package/dist/esm/pagination-plugin.js.map +1 -1
- package/dist/esm/product-price-sort.d.ts +0 -9
- package/dist/esm/product-price-sort.d.ts.map +1 -1
- package/dist/esm/product-price-sort.js +0 -11
- package/dist/esm/product-price-sort.js.map +1 -1
- package/dist/esm/range-control.d.ts +45 -0
- package/dist/esm/range-control.d.ts.map +1 -0
- package/dist/esm/range-control.js +137 -0
- package/dist/esm/range-control.js.map +1 -0
- package/dist/esm/row-order.d.ts +20 -0
- package/dist/esm/row-order.d.ts.map +1 -0
- package/dist/esm/row-order.js +41 -0
- package/dist/esm/row-order.js.map +1 -0
- package/dist/esm/search-input.d.ts +42 -0
- package/dist/esm/search-input.d.ts.map +1 -0
- package/dist/esm/search-input.js +129 -0
- package/dist/esm/search-input.js.map +1 -0
- package/dist/esm/sort-utils.d.ts +10 -0
- package/dist/esm/sort-utils.d.ts.map +1 -1
- package/dist/esm/sort-utils.js +20 -0
- package/dist/esm/sort-utils.js.map +1 -1
- package/dist/esm/transformations/blog-adjacent-posts.d.ts +11 -1
- package/dist/esm/transformations/blog-adjacent-posts.d.ts.map +1 -1
- package/dist/esm/transformations/blog-adjacent-posts.js +14 -1
- package/dist/esm/transformations/blog-adjacent-posts.js.map +1 -1
- package/dist/esm/transformations/blog-comments.d.ts +1 -1
- package/dist/esm/transformations/blog-comments.d.ts.map +1 -1
- package/dist/esm/transformations/blog-comments.js +1 -1
- package/dist/esm/transformations/blog-comments.js.map +1 -1
- package/dist/esm/transformations/blog-post.d.ts +14 -0
- package/dist/esm/transformations/blog-post.d.ts.map +1 -1
- package/dist/esm/transformations/blog-post.js +4 -1
- package/dist/esm/transformations/blog-post.js.map +1 -1
- package/dist/esm/transformations/booking-item.d.ts +24 -0
- package/dist/esm/transformations/booking-item.d.ts.map +1 -0
- package/dist/esm/transformations/booking-item.js +23 -0
- package/dist/esm/transformations/booking-item.js.map +1 -0
- package/dist/esm/transformations/heading-anchors.d.ts +32 -8
- package/dist/esm/transformations/heading-anchors.d.ts.map +1 -1
- package/dist/esm/transformations/heading-anchors.js +33 -9
- package/dist/esm/transformations/heading-anchors.js.map +1 -1
- package/dist/esm/transformations/index.d.ts +27 -13
- package/dist/esm/transformations/index.d.ts.map +1 -1
- package/dist/esm/transformations/index.js +72 -16
- package/dist/esm/transformations/index.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/utils.d.ts.map +1 -1
- package/dist/esm/utils.js +52 -3
- package/dist/esm/utils.js.map +1 -1
- package/package.json +5 -5
- package/src/count-effect.ts +31 -8
- package/src/fetchers/pg-client-import.ts +16 -0
- package/src/fetchers/postgresql.ts +25 -23
- package/src/fetchers/raw-query.ts +2 -1
- package/src/fetchers/rest-api.ts +3 -1
- package/src/fetchers/teleport.ts +22 -23
- package/src/fetchers/utils/browser-row-policy.ts +10 -20
- package/src/filter-utils.ts +102 -28
- package/src/infinite-scroll.ts +240 -79
- package/src/list-sort-order.ts +34 -0
- package/src/pagination-controls.ts +26 -3
- package/src/pagination-plugin.ts +370 -306
- package/src/product-price-sort.ts +0 -11
- package/src/range-control.ts +207 -0
- package/src/row-order.ts +55 -0
- package/src/search-input.ts +190 -0
- package/src/sort-utils.ts +25 -0
- package/src/transformations/blog-adjacent-posts.ts +89 -3
- package/src/transformations/blog-comments.ts +5 -5
- package/src/transformations/blog-post.ts +64 -13
- package/src/transformations/booking-item.ts +71 -0
- package/src/transformations/heading-anchors.ts +79 -16
- package/src/transformations/index.ts +104 -14
- package/src/utils.ts +74 -3
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import * as types from '@babel/types'
|
|
2
|
+
import generator from '@babel/generator'
|
|
3
|
+
import {
|
|
4
|
+
ChunkType,
|
|
5
|
+
FileType,
|
|
6
|
+
ComponentStructure,
|
|
7
|
+
ChunkDefinition,
|
|
8
|
+
} from '@teleporthq/teleport-types'
|
|
9
|
+
import { createNextArrayMapperPaginationPlugin } from '../src/pagination-plugin'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* A PLAIN list — no pagination, no search — fetches with the sort its
|
|
13
|
+
* repeater carries, like every other list: the three paginated / searchable
|
|
14
|
+
* kinds rebuild their params with it, while a plain list's params were kept
|
|
15
|
+
* as they came and the sort never reached the fetch, so the rows arrived in
|
|
16
|
+
* the table's own order whatever the editor said.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const element = (name: string, attributes: types.JSXAttribute[] = []) =>
|
|
20
|
+
types.jsxElement(
|
|
21
|
+
types.jsxOpeningElement(types.jsxIdentifier(name), attributes, true),
|
|
22
|
+
null,
|
|
23
|
+
[],
|
|
24
|
+
true
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
const makeDataProviderJSX = (): types.JSXElement =>
|
|
28
|
+
element('DataProvider', [
|
|
29
|
+
types.jsxAttribute(
|
|
30
|
+
types.jsxIdentifier('name'),
|
|
31
|
+
types.jsxExpressionContainer(types.stringLiteral('items'))
|
|
32
|
+
),
|
|
33
|
+
types.jsxAttribute(
|
|
34
|
+
types.jsxIdentifier('renderSuccess'),
|
|
35
|
+
types.jsxExpressionContainer(
|
|
36
|
+
types.arrowFunctionExpression(
|
|
37
|
+
[types.identifier('items')],
|
|
38
|
+
element('Repeater', [
|
|
39
|
+
types.jsxAttribute(
|
|
40
|
+
types.jsxIdentifier('renderItem'),
|
|
41
|
+
types.jsxExpressionContainer(
|
|
42
|
+
types.arrowFunctionExpression([types.identifier('post')], element('div'))
|
|
43
|
+
)
|
|
44
|
+
),
|
|
45
|
+
])
|
|
46
|
+
)
|
|
47
|
+
)
|
|
48
|
+
),
|
|
49
|
+
])
|
|
50
|
+
|
|
51
|
+
const makeComponentChunk = (): ChunkDefinition => ({
|
|
52
|
+
name: 'jsx-component',
|
|
53
|
+
type: ChunkType.AST,
|
|
54
|
+
fileType: FileType.JS,
|
|
55
|
+
linkAfter: [],
|
|
56
|
+
content: types.variableDeclaration('const', [
|
|
57
|
+
types.variableDeclarator(
|
|
58
|
+
types.identifier('PostsList'),
|
|
59
|
+
types.arrowFunctionExpression(
|
|
60
|
+
[types.identifier('props')],
|
|
61
|
+
types.blockStatement([types.returnStatement(makeDataProviderJSX())])
|
|
62
|
+
)
|
|
63
|
+
),
|
|
64
|
+
]),
|
|
65
|
+
meta: {},
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
type SortKind = 'fixed' | 'state' | 'none'
|
|
69
|
+
|
|
70
|
+
const SORTS: Record<SortKind, Record<string, unknown>> = {
|
|
71
|
+
fixed: {
|
|
72
|
+
sort: { type: 'static', content: 'title' },
|
|
73
|
+
sortDirection: { type: 'static', content: 'asc' },
|
|
74
|
+
},
|
|
75
|
+
state: {
|
|
76
|
+
sort: { type: 'expr', content: 'sortBy.split("-")[0]' },
|
|
77
|
+
sortDirection: { type: 'expr', content: 'sortBy.split("-")[1]' },
|
|
78
|
+
},
|
|
79
|
+
none: {},
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const runPlugin = async (
|
|
83
|
+
sort: SortKind,
|
|
84
|
+
options: { legacySorts?: boolean; params?: boolean; prefetched?: boolean } = {}
|
|
85
|
+
): Promise<string> => {
|
|
86
|
+
const chunk = makeComponentChunk()
|
|
87
|
+
if (options.prefetched) {
|
|
88
|
+
// A page's list, seeded with its server prefetch.
|
|
89
|
+
const provider = (
|
|
90
|
+
(chunk.content as types.VariableDeclaration).declarations[0]
|
|
91
|
+
.init as types.ArrowFunctionExpression
|
|
92
|
+
).body as types.BlockStatement
|
|
93
|
+
const jsx = (provider.body[0] as types.ReturnStatement).argument as types.JSXElement
|
|
94
|
+
jsx.openingElement.attributes.push(
|
|
95
|
+
types.jsxAttribute(
|
|
96
|
+
types.jsxIdentifier('initialData'),
|
|
97
|
+
types.jsxExpressionContainer(
|
|
98
|
+
types.memberExpression(types.identifier('props'), types.identifier('items'))
|
|
99
|
+
)
|
|
100
|
+
)
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
if (options.params) {
|
|
104
|
+
// The params the data-source plugin writes for a plain list: its filters.
|
|
105
|
+
const provider = (
|
|
106
|
+
(chunk.content as types.VariableDeclaration).declarations[0]
|
|
107
|
+
.init as types.ArrowFunctionExpression
|
|
108
|
+
).body as types.BlockStatement
|
|
109
|
+
const jsx = (provider.body[0] as types.ReturnStatement).argument as types.JSXElement
|
|
110
|
+
jsx.openingElement.attributes.push(
|
|
111
|
+
types.jsxAttribute(
|
|
112
|
+
types.jsxIdentifier('params'),
|
|
113
|
+
types.jsxExpressionContainer(
|
|
114
|
+
types.objectExpression([
|
|
115
|
+
types.objectProperty(types.identifier('filters'), types.stringLiteral('[]')),
|
|
116
|
+
])
|
|
117
|
+
)
|
|
118
|
+
)
|
|
119
|
+
)
|
|
120
|
+
}
|
|
121
|
+
const structure: ComponentStructure = {
|
|
122
|
+
uidl: {
|
|
123
|
+
name: 'PostsList',
|
|
124
|
+
node: {
|
|
125
|
+
type: 'data-source-list',
|
|
126
|
+
content: {
|
|
127
|
+
renderPropIdentifier: 'items',
|
|
128
|
+
resourceDefinition: {
|
|
129
|
+
dataSourceId: 'ds1',
|
|
130
|
+
tableName: 'posts',
|
|
131
|
+
dataSourceType: 'postgresql',
|
|
132
|
+
},
|
|
133
|
+
resource: {
|
|
134
|
+
params: {
|
|
135
|
+
queryColumns: { content: ['title'] },
|
|
136
|
+
...(options.legacySorts
|
|
137
|
+
? { sorts: { content: [{ field: 'created_at', order: 'desc' }] } }
|
|
138
|
+
: {}),
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
nodes: {
|
|
142
|
+
success: {
|
|
143
|
+
type: 'cms-list-repeater',
|
|
144
|
+
content: {
|
|
145
|
+
renderPropIdentifier: 'post',
|
|
146
|
+
nodes: { list: { type: 'element', content: { elementType: 'div' } } },
|
|
147
|
+
...SORTS[sort],
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
chunks: [chunk],
|
|
155
|
+
dependencies: {},
|
|
156
|
+
options: {
|
|
157
|
+
dataSources: {
|
|
158
|
+
ds1: {
|
|
159
|
+
id: 'ds1',
|
|
160
|
+
name: 'Content',
|
|
161
|
+
type: 'postgresql',
|
|
162
|
+
config: { host: 'h', database: 'd', user: 'u', password: 'p' },
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
extractedResources: {},
|
|
166
|
+
},
|
|
167
|
+
} as never
|
|
168
|
+
await createNextArrayMapperPaginationPlugin()(structure)
|
|
169
|
+
return generator(chunk.content as types.Node).code
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const squash = (code: string) => code.replace(/\s+/g, ' ')
|
|
173
|
+
|
|
174
|
+
describe('a plain list fetches with its repeater’s sort', () => {
|
|
175
|
+
it('sends a sort the editor fixed', async () => {
|
|
176
|
+
const code = squash(await runPlugin('fixed'))
|
|
177
|
+
expect(code).toContain(
|
|
178
|
+
'params={useMemo(() => ({ sorts: JSON.stringify([{ field: "title", order: "asc" }]) }), [])}'
|
|
179
|
+
)
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
it('sends a sort bound to state, and refetches when the state changes', async () => {
|
|
183
|
+
const code = squash(await runPlugin('state'))
|
|
184
|
+
expect(code).toContain(
|
|
185
|
+
'sorts: JSON.stringify([{ field: sortBy.split("-")?.[0], order: sortBy.split("-")?.[1] }])'
|
|
186
|
+
)
|
|
187
|
+
expect(code).toMatch(/\}\), \[sortBy\]\)\}/)
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
it('adds the sort beside the params the list already had', async () => {
|
|
191
|
+
const code = squash(await runPlugin('fixed', { params: true }))
|
|
192
|
+
expect(code).toContain(
|
|
193
|
+
'params={useMemo(() => ({ filters: "[]", sorts: JSON.stringify([{ field: "title", order: "asc" }]) }), [])}'
|
|
194
|
+
)
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
it('keeps the resource’s own sorts first, as every other list does', async () => {
|
|
198
|
+
const code = squash(await runPlugin('fixed', { legacySorts: true }))
|
|
199
|
+
expect(code).toContain('sorts: JSON.stringify([{ field: "created_at", order: "desc" }])')
|
|
200
|
+
expect(code).not.toContain('field: "title"')
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
it('drops the prefetched rows for a sort bound to state, which the server cannot know', async () => {
|
|
204
|
+
expect(squash(await runPlugin('state', { prefetched: true }))).not.toContain('initialData')
|
|
205
|
+
expect(squash(await runPlugin('fixed', { prefetched: true }))).toContain(
|
|
206
|
+
'initialData={props.items}'
|
|
207
|
+
)
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
it('leaves a list without a sort as it was', async () => {
|
|
211
|
+
const code = squash(await runPlugin('none'))
|
|
212
|
+
expect(code).not.toContain('sorts')
|
|
213
|
+
expect(code).not.toContain('params=')
|
|
214
|
+
})
|
|
215
|
+
})
|
|
@@ -5,12 +5,12 @@ import {
|
|
|
5
5
|
buildProductEffectivePriceSql,
|
|
6
6
|
generateSortFallbackFieldHelper,
|
|
7
7
|
generateSortFieldSqlHelper,
|
|
8
|
-
generateSortTiebreakSql,
|
|
9
8
|
supportsProductPriceSort,
|
|
10
9
|
} from '../src/product-price-sort'
|
|
11
10
|
import { generatePostgreSQLFetcher } from '../src/fetchers/postgresql'
|
|
12
11
|
import { generateTeleportFetcher } from '../src/fetchers/teleport'
|
|
13
12
|
import { generateDataSourceFetcher } from '../src/data-source-fetchers'
|
|
13
|
+
import { generateRowOrderTiebreakHelper, rowIdentityColumn } from '../src/row-order'
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Ordering a products list by what customers actually pay.
|
|
@@ -121,8 +121,8 @@ describe('the generated Postgres route', () => {
|
|
|
121
121
|
it('keeps a plain-column ORDER BY to fall back to', () => {
|
|
122
122
|
// If a database ever rejects the sub-select, the page must degrade to the
|
|
123
123
|
// previous ordering rather than serve nothing.
|
|
124
|
-
expect(productsRoute).toContain('const
|
|
125
|
-
expect(productsRoute).toContain('if (!
|
|
124
|
+
expect(productsRoute).toContain('const usedRewrittenSort = orderBySql !== plainOrderBySql')
|
|
125
|
+
expect(productsRoute).toContain('if (!usedRewrittenSort) throw sortError')
|
|
126
126
|
expect(productsRoute).toContain('baseSql + plainOrderBySql + sqlTail')
|
|
127
127
|
})
|
|
128
128
|
|
|
@@ -201,23 +201,57 @@ describe('degrading safely', () => {
|
|
|
201
201
|
})
|
|
202
202
|
|
|
203
203
|
describe('stable pagination', () => {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
204
|
+
// Rows that share every requested key have no order of their own: "sort by
|
|
205
|
+
// discount" ties every undiscounted product at zero, an import dates hundreds
|
|
206
|
+
// of articles alike. Equal rows can appear on two pages, or on none.
|
|
207
|
+
const tiebreakOf = (identityColumn: string | null) =>
|
|
208
|
+
// eslint-disable-next-line no-new-func
|
|
209
|
+
new Function(`${generateRowOrderTiebreakHelper(identityColumn)}\nreturn rowOrderTiebreak`)()
|
|
210
|
+
|
|
211
|
+
it("ends every order with the row's own key, in the order's direction", () => {
|
|
212
|
+
const tiebreak = tiebreakOf('id')
|
|
213
|
+
expect(tiebreak(['created_at'], 'DESC')).toBe(', "id" DESC')
|
|
214
|
+
expect(tiebreak(['price'], 'ASC')).toBe(', "id" ASC')
|
|
215
|
+
expect(tiebreak(['id'], 'ASC')).toBe('')
|
|
216
|
+
expect(tiebreakOf(null)(['created_at'], 'DESC')).toBe('')
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
it("takes the table's primary key, else its id, and the products table's id", () => {
|
|
220
|
+
const saved = (columns: unknown[]) => ({ selectedTables: { posts: { columns } } })
|
|
221
|
+
expect(
|
|
222
|
+
rowIdentityColumn(saved([{ name: 'sku', isPrimaryKey: true }, { name: 'id' }]), 'posts')
|
|
223
|
+
).toBe('sku')
|
|
224
|
+
expect(rowIdentityColumn(saved([{ name: 'title' }, { name: 'id' }]), 'posts')).toBe('id')
|
|
225
|
+
expect(rowIdentityColumn(saved([{ name: 'title' }]), 'posts')).toBeNull()
|
|
226
|
+
expect(rowIdentityColumn({}, 'teleport_products')).toBe('id')
|
|
227
|
+
expect(rowIdentityColumn({}, 'teleport_orders')).toBeNull()
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
it('breaks ties on every listing a visitor sorts: the blog listing and the booking page too', () => {
|
|
231
|
+
// "Sort by reading time" ties every five-minute post, "by price" every
|
|
232
|
+
// item at the same price.
|
|
233
|
+
expect(rowIdentityColumn({}, 'teleport_blog_posts')).toBe('id')
|
|
234
|
+
expect(rowIdentityColumn({}, 'teleport_booking_items')).toBe('id')
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
it('is applied to the real and the fallback ORDER BY, and to a single sort column', () => {
|
|
238
|
+
for (const route of [
|
|
239
|
+
generatePostgreSQLFetcher(PG_CONFIG, 'teleport_products'),
|
|
240
|
+
generateTeleportFetcher(
|
|
241
|
+
{
|
|
242
|
+
selectedTables: {
|
|
243
|
+
teleport_help_articles: { columns: [{ name: 'id', isPrimaryKey: true }] },
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
'teleport_help_articles'
|
|
247
|
+
),
|
|
248
|
+
]) {
|
|
249
|
+
const orderByLines = route.split('\n').filter((line) => line.includes('ORDER BY ${'))
|
|
250
|
+
expect(orderByLines.length).toBeGreaterThanOrEqual(3)
|
|
251
|
+
orderByLines.forEach((line) => expect(line).toMatch(/tiebreak|rowOrderTiebreak/))
|
|
252
|
+
expect(route).toContain('const rowOrderTiebreak = (fields, direction) =>')
|
|
253
|
+
expect(() => parse(route, { sourceType: 'module', plugins: ['jsx'] })).not.toThrow()
|
|
254
|
+
}
|
|
221
255
|
})
|
|
222
256
|
})
|
|
223
257
|
|
|
@@ -247,12 +281,11 @@ describe('the fetcher a generated storefront actually gets', () => {
|
|
|
247
281
|
})
|
|
248
282
|
|
|
249
283
|
it('keeps the plain-column fallback and the tiebreaker', () => {
|
|
250
|
-
expect(teleportProducts).toContain(
|
|
251
|
-
|
|
252
|
-
)
|
|
253
|
-
expect(teleportProducts).toContain('if (!usedDiscountAwareSort) throw sortError')
|
|
284
|
+
expect(teleportProducts).toContain('const usedRewrittenSort = orderBySql !== plainOrderBySql')
|
|
285
|
+
expect(teleportProducts).toContain('if (!usedRewrittenSort) throw sortError')
|
|
254
286
|
expect(teleportProducts).toContain('baseSql + plainOrderBySql + sqlTail')
|
|
255
|
-
expect(teleportProducts).toContain('
|
|
287
|
+
expect(teleportProducts).toContain('const rowOrderTiebreak = (fields, direction) =>')
|
|
288
|
+
expect(teleportProducts).toMatch(/\$\{tiebreak\}/)
|
|
256
289
|
})
|
|
257
290
|
|
|
258
291
|
it('parses as valid JavaScript', () => {
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import * as types from '@babel/types'
|
|
2
|
+
import generator from '@babel/generator'
|
|
3
|
+
import { ComponentStructure } from '@teleporthq/teleport-types'
|
|
4
|
+
import { createNextArrayMapperPaginationPlugin } from '../src/pagination-plugin'
|
|
5
|
+
import {
|
|
6
|
+
makeUidlNode,
|
|
7
|
+
makeWidgetComponentChunk,
|
|
8
|
+
RANGE_DRAWN_TEXT,
|
|
9
|
+
type RepeaterOptions,
|
|
10
|
+
} from './_helpers/pagination-widget-fixture'
|
|
11
|
+
|
|
12
|
+
type ControlOptions = Parameters<typeof makeWidgetComponentChunk>[0]
|
|
13
|
+
|
|
14
|
+
const runPlugin = async (repeater: RepeaterOptions, controls: ControlOptions): Promise<string> => {
|
|
15
|
+
const chunk = makeWidgetComponentChunk(controls)
|
|
16
|
+
const structure: ComponentStructure = {
|
|
17
|
+
uidl: { name: 'TestComponent', node: makeUidlNode(repeater) },
|
|
18
|
+
chunks: [chunk],
|
|
19
|
+
dependencies: {},
|
|
20
|
+
options: { dataSources: {}, extractedResources: {} },
|
|
21
|
+
} as never
|
|
22
|
+
await createNextArrayMapperPaginationPlugin()(structure)
|
|
23
|
+
return generator(chunk.content as types.Node).code
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const collapse = (code: string): string => code.replace(/\s+/g, ' ')
|
|
27
|
+
|
|
28
|
+
const TOTAL_STATE = 'const [ds_0_total, setDs_0_total] = useState(null)'
|
|
29
|
+
const DRAWN = `ds_0_total === null ? "${RANGE_DRAWN_TEXT}" :`
|
|
30
|
+
const FROM_BY_PAGE = '(ds_0_total === 0 ? 0 : (ds_0_page - 1) * 20 + 1).toLocaleString("en-US")'
|
|
31
|
+
const FROM_FIRST_ROW = '(ds_0_total === 0 ? 0 : 1).toLocaleString("en-US")'
|
|
32
|
+
const TO = 'Math.min(ds_0_page * 20, ds_0_total).toLocaleString("en-US")'
|
|
33
|
+
const TOTAL = 'ds_0_total.toLocaleString("en-US")'
|
|
34
|
+
|
|
35
|
+
describe('pagination plugin — range control', () => {
|
|
36
|
+
it('fills the authored words with the page window in buttons mode', async () => {
|
|
37
|
+
const flat = collapse(await runPlugin({}, { controls: ['previous', 'range', 'next'] }))
|
|
38
|
+
|
|
39
|
+
// The total is a state of its own — `maxPages` cannot give it back — and
|
|
40
|
+
// the count effect fills both from the same response.
|
|
41
|
+
expect(flat).toContain(TOTAL_STATE)
|
|
42
|
+
expect(flat).toContain('setDs_0_maxPages(')
|
|
43
|
+
expect(flat).toContain('setDs_0_total(data.count)')
|
|
44
|
+
|
|
45
|
+
// The drawn text stays until the count has answered; then the template.
|
|
46
|
+
expect(flat).toContain(`${DRAWN} \`Showing \${${FROM_BY_PAGE}}–\${${TO}} of \${${TOTAL}}\``)
|
|
47
|
+
// The marker and template ride along, so the DOM carries the contract.
|
|
48
|
+
expect(flat).toContain('data-tq-pagination-control="range"')
|
|
49
|
+
expect(flat).toContain('data-tq-range-template=')
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('counts from the first row in an appending list and survives the mode pruning', async () => {
|
|
53
|
+
const flat = collapse(
|
|
54
|
+
await runPlugin(
|
|
55
|
+
{ infiniteScroll: true, infiniteScrollLoadMore: true },
|
|
56
|
+
{ controls: ['previous', 'range', 'load-more', 'next'] }
|
|
57
|
+
)
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
// Previous/Next are pruned for an appending list; the range is not.
|
|
61
|
+
expect(flat).not.toContain('thq-previous-elm')
|
|
62
|
+
expect(flat).not.toContain('thq-next-elm')
|
|
63
|
+
expect(flat).toContain('thq-load-more-elm')
|
|
64
|
+
expect(flat).toContain('data-tq-pagination-control="range"')
|
|
65
|
+
|
|
66
|
+
// Everything loaded so far: 1 .. min(pages × perPage, total).
|
|
67
|
+
expect(flat).toContain(`${DRAWN} \`Showing \${${FROM_FIRST_ROW}}–\${${TO}} of \${${TOTAL}}\``)
|
|
68
|
+
expect(flat).not.toContain(FROM_BY_PAGE)
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
it('is kept and wired beside a sentinel-driven infinite scroll too', async () => {
|
|
72
|
+
const flat = collapse(await runPlugin({ infiniteScroll: true }, { controls: ['range'] }))
|
|
73
|
+
|
|
74
|
+
expect(flat).toContain('ds_0_sentinelRef')
|
|
75
|
+
expect(flat).toContain(TOTAL_STATE)
|
|
76
|
+
expect(flat).toContain(FROM_FIRST_ROW)
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
it('survives numbered mode with the page window', async () => {
|
|
80
|
+
const flat = collapse(
|
|
81
|
+
await runPlugin(
|
|
82
|
+
{ paginationMode: 'numbered' },
|
|
83
|
+
{ controls: ['first', 'previous', 'pages', 'range', 'next', 'last'] }
|
|
84
|
+
)
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
expect(flat).toContain('ds_0_pageTokens.map(token =>')
|
|
88
|
+
expect(flat).toContain('data-tq-pagination-control="range"')
|
|
89
|
+
expect(flat).toContain(FROM_BY_PAGE)
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
it('reads the page off the combined state beside a search input', async () => {
|
|
93
|
+
const flat = collapse(
|
|
94
|
+
await runPlugin({ searchEnabled: true }, { controls: ['previous', 'range', 'next'] })
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
expect(flat).toContain(TOTAL_STATE)
|
|
98
|
+
expect(flat).toContain('setDs_0_total(data.count)')
|
|
99
|
+
expect(flat).toContain(
|
|
100
|
+
'(ds_0_total === 0 ? 0 : (ds_0_state.page - 1) * 20 + 1).toLocaleString("en-US")'
|
|
101
|
+
)
|
|
102
|
+
expect(flat).toContain('Math.min(ds_0_state.page * 20, ds_0_total).toLocaleString("en-US")')
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
it('reads a template the JSX printer escaped the braces of', async () => {
|
|
106
|
+
const flat = collapse(
|
|
107
|
+
await runPlugin(
|
|
108
|
+
{},
|
|
109
|
+
{
|
|
110
|
+
controls: ['range'],
|
|
111
|
+
rangeTemplate: 'Showing {from}–{to} of {total}',
|
|
112
|
+
}
|
|
113
|
+
)
|
|
114
|
+
)
|
|
115
|
+
expect(flat).not.toContain('`Showing {')
|
|
116
|
+
expect(flat).toMatch(/`Showing \$\{[^`]*–\$\{[^`]*of \$\{[^`]*`/)
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
it('falls back to "{from}–{to} of {total}" when no template is authored', async () => {
|
|
120
|
+
const flat = collapse(await runPlugin({}, { controls: ['range'], rangeTemplate: null }))
|
|
121
|
+
|
|
122
|
+
expect(flat).not.toContain('data-tq-range-template')
|
|
123
|
+
expect(flat).toContain(`${DRAWN} \`\${${FROM_BY_PAGE}}–\${${TO}} of \${${TOTAL}}\``)
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
it('wires a range outside every widget to the mapper it names, wherever it sits', async () => {
|
|
127
|
+
// Placed BEFORE the provider — a toolbar above the list — so the
|
|
128
|
+
// container-ownership rule could never have reached it.
|
|
129
|
+
const flat = collapse(
|
|
130
|
+
await runPlugin(
|
|
131
|
+
{ nodeId: 'mapper-1' },
|
|
132
|
+
{ controls: ['previous', 'next'], standaloneRange: { forNodeId: 'mapper-1' } }
|
|
133
|
+
)
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
expect(flat).toContain('data-tq-pagination-for="mapper-1"')
|
|
137
|
+
expect(flat).toContain(TOTAL_STATE)
|
|
138
|
+
expect(flat).toContain(`${DRAWN} \`Showing \${${FROM_BY_PAGE}}–\${${TO}} of \${${TOTAL}}\``)
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
it('leaves a range naming a mapper this component does not render as drawn', async () => {
|
|
142
|
+
const flat = collapse(
|
|
143
|
+
await runPlugin(
|
|
144
|
+
{ nodeId: 'mapper-1' },
|
|
145
|
+
{ controls: ['previous', 'next'], standaloneRange: { forNodeId: 'someone-else' } }
|
|
146
|
+
)
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
expect(flat).toContain(`>${RANGE_DRAWN_TEXT}</div>`)
|
|
150
|
+
expect(flat).not.toContain('ds_0_total === null')
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
it('changes nothing for a component without a range control', async () => {
|
|
154
|
+
const flat = collapse(await runPlugin({}, { controls: ['previous', 'next'] }))
|
|
155
|
+
|
|
156
|
+
expect(flat).not.toContain('ds_0_total')
|
|
157
|
+
expect(flat).not.toContain('setDs_0_total')
|
|
158
|
+
})
|
|
159
|
+
})
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { generateRESTAPIFetcher } from '../src/fetchers/rest-api'
|
|
2
|
+
|
|
3
|
+
describe('REST API fetcher with API key authorization', () => {
|
|
4
|
+
/*
|
|
5
|
+
* The editor's data fetcher sends the key as `X-API-Key`. The live site sent
|
|
6
|
+
* `Authorization: ApiKey …`, so a source that worked on the canvas failed once
|
|
7
|
+
* published.
|
|
8
|
+
*/
|
|
9
|
+
it('sends the key in the same header the editor sends', () => {
|
|
10
|
+
const code = generateRESTAPIFetcher({
|
|
11
|
+
url: 'https://api.example.com/items',
|
|
12
|
+
method: 'GET',
|
|
13
|
+
authorization: { type: 'api-key', credentials: { apiKey: 'k-1' } },
|
|
14
|
+
})
|
|
15
|
+
expect(code).toContain("headers['X-API-Key'] = 'k-1'")
|
|
16
|
+
expect(code).not.toContain('ApiKey ')
|
|
17
|
+
})
|
|
18
|
+
})
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import * as types from '@babel/types'
|
|
2
|
+
import generator from '@babel/generator'
|
|
3
|
+
import { ComponentStructure } from '@teleporthq/teleport-types'
|
|
4
|
+
import { createNextArrayMapperPaginationPlugin } from '../src/pagination-plugin'
|
|
5
|
+
import {
|
|
6
|
+
makeMultiMapperUidl,
|
|
7
|
+
makeWidgetComponentChunk,
|
|
8
|
+
type RepeaterOptions,
|
|
9
|
+
} from './_helpers/pagination-widget-fixture'
|
|
10
|
+
|
|
11
|
+
type ControlOptions = Parameters<typeof makeWidgetComponentChunk>[0]
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A page's OWN search box, marked `data-tq-search-for` with its mapper's node
|
|
15
|
+
* id, is wired like the platform's `search-input`: controlled by the mapper's
|
|
16
|
+
* query state. It is paired by the id it names, never by its place among the
|
|
17
|
+
* platform inputs.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const runPlugin = async (
|
|
21
|
+
repeaters: RepeaterOptions[],
|
|
22
|
+
controls: ControlOptions
|
|
23
|
+
): Promise<string> => {
|
|
24
|
+
const chunk = makeWidgetComponentChunk(controls)
|
|
25
|
+
const structure: ComponentStructure = {
|
|
26
|
+
uidl: { name: 'TestComponent', node: makeMultiMapperUidl(repeaters) },
|
|
27
|
+
chunks: [chunk],
|
|
28
|
+
dependencies: {},
|
|
29
|
+
options: { dataSources: {}, extractedResources: {} },
|
|
30
|
+
} as never
|
|
31
|
+
await createNextArrayMapperPaginationPlugin()(structure)
|
|
32
|
+
return generator(chunk.content as types.Node).code
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const collapse = (code: string): string => code.replace(/\s+/g, ' ')
|
|
36
|
+
|
|
37
|
+
const wiredTo = (index: number): string =>
|
|
38
|
+
`onChange={e => setDs_${index}_searchQuery(e.target.value)} value={ds_${index}_searchQuery}`
|
|
39
|
+
|
|
40
|
+
describe('pagination plugin — a page’s own search box', () => {
|
|
41
|
+
it('controls a marked input by the query of the mapper it names, and keeps Enter from submitting', async () => {
|
|
42
|
+
const flat = collapse(
|
|
43
|
+
await runPlugin([{ searchEnabled: true, nodeId: 'TQ_orders' }], {
|
|
44
|
+
controls: ['previous', 'next'],
|
|
45
|
+
standaloneSearch: [{ name: 'hm-search', forNodeId: 'TQ_orders' }],
|
|
46
|
+
})
|
|
47
|
+
)
|
|
48
|
+
expect(flat).toContain(`name="hm-search" data-tq-search-for="TQ_orders" ${wiredTo(0)}`)
|
|
49
|
+
expect(flat).toContain('onKeyDown={e => { if (e.key === "Enter") e.preventDefault(); }}')
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('pairs by the id named, whatever the order: the platform input keeps its place', async () => {
|
|
53
|
+
const flat = collapse(
|
|
54
|
+
await runPlugin(
|
|
55
|
+
[
|
|
56
|
+
{ searchEnabled: true, nodeId: 'TQ_jobs' },
|
|
57
|
+
{ searchEnabled: true, nodeId: 'TQ_orders' },
|
|
58
|
+
],
|
|
59
|
+
{
|
|
60
|
+
controls: ['previous', 'next'],
|
|
61
|
+
mappers: 2,
|
|
62
|
+
standaloneSearch: [
|
|
63
|
+
{ name: 'hm-search', forNodeId: 'TQ_orders' },
|
|
64
|
+
{ name: 'platform-search' },
|
|
65
|
+
],
|
|
66
|
+
}
|
|
67
|
+
)
|
|
68
|
+
)
|
|
69
|
+
// The marked box searches the second mapper; the platform box, first of its kind, the first.
|
|
70
|
+
expect(flat).toContain(`data-tq-search-for="TQ_orders" ${wiredTo(1)}`)
|
|
71
|
+
expect(flat).toContain(
|
|
72
|
+
`name="platform-search" className="products-list-search-input" ${wiredTo(0)}`
|
|
73
|
+
)
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
it('leaves a marked input alone when no search-enabled mapper carries its id', async () => {
|
|
77
|
+
const flat = collapse(
|
|
78
|
+
await runPlugin([{ searchEnabled: true, nodeId: 'TQ_orders' }], {
|
|
79
|
+
controls: ['previous', 'next'],
|
|
80
|
+
standaloneSearch: [{ name: 'hm-search', forNodeId: 'TQ_elsewhere' }],
|
|
81
|
+
})
|
|
82
|
+
)
|
|
83
|
+
expect(flat).toContain('name="hm-search" data-tq-search-for="TQ_elsewhere" />')
|
|
84
|
+
expect(flat).not.toContain('setDs_0_searchQuery(e.target.value)')
|
|
85
|
+
})
|
|
86
|
+
})
|