ts_schema_spec 0.6.0 → 0.6.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dcc02f190a1fcbe41e89aaab3f8714c6cc5d189372297d4bfb716af2d7a97e8e
4
- data.tar.gz: ac904c2a071466249b79f9b514b4f5c06ab8f746b17a00ac3703dae257ad93d3
3
+ metadata.gz: 1d8e48873074ac373b562a69c895679dc7afbe1a21d81df9910f8e9f766c2fcc
4
+ data.tar.gz: bdc53ec65a7c01ff8c63d9ce95525cf01587d25bbf0726b7566a129724401fff
5
5
  SHA512:
6
- metadata.gz: b42d96309d3f9beaa23ac086f5057c0a87a281d18548aad96d7d24cb6695e84920301d5041a22a9c14f60f8193d4d99ae255dcc4b7262675a5b8d779ad49fc6b
7
- data.tar.gz: 5c7ac0e02c49f4c363221e8569e510eb068ba780930a219080b339150a647dcb7dfc010cececa1cbde81e0378c59926ea2ca85742476a306df51bf2ca8d03db5
6
+ metadata.gz: 482f0478728009f5bc10ac65f2a9046c5c1d28393d394bddfbd3c59ad4f029a26d9b9eb9587006d4b065756c3b6e6fc59eea95fc60e4f136b8454760cc7eb0e7
7
+ data.tar.gz: 6a65b04776bd6c9eb5c12a6bf96b97cbd939d6e7215171e71e71c10f8fbee8f9c4925bb59444110714d262a05e4c0793d73c62da394b48798271bb689d56012c
data/README.md CHANGED
@@ -8,7 +8,7 @@ Built for RSpec, but could be ported to other test frameworks (Minitest, etc.).
8
8
  `react_component_props`, an optional React-specific helper, reads props out of
9
9
  rendered mounts.
10
10
 
11
- React is the case this gem was built for, not a requirement. `match_schema`
11
+ React is the case this gem was built for, not a requirement. `match_ts_schema`
12
12
  checks any payload against any exported TypeScript type, so a Stimulus
13
13
  controller or a plain fetch client works the same way.
14
14
 
@@ -101,7 +101,7 @@ it "matches AccountPayload" do
101
101
 
102
102
  expect(response).to be_successful
103
103
  expect(response.parsed_body["accounts"])
104
- .to match_schema("app/javascript/types/account.ts", "AccountPayload")
104
+ .to match_ts_schema("app/javascript/types/account.ts", "AccountPayload")
105
105
  end
106
106
  ```
107
107
 
@@ -134,28 +134,31 @@ describe "the props handed to RoleMatrix" do
134
134
 
135
135
  expect(response).to be_successful
136
136
  props = react_component_props("RoleMatrix")
137
- expect(props).to match_schema(role_matrix, "RoleMatrixProps")
137
+ expect(props).to match_ts_schema(role_matrix, "RoleMatrixProps")
138
138
  end
139
139
  end
140
140
  ```
141
141
 
142
- `match_schema` accepts a hash or an array of hashes. Given an array, it
142
+ `match_ts_schema` accepts a hash or an array of hashes. Given an array, it
143
143
  validates every item and fails on an empty one — in both directions, so
144
- `to_not match_schema` does not pass vacuously either. A page that stopped
144
+ `to_not match_ts_schema` does not pass vacuously either. A page that stopped
145
145
  rendering the component fails rather than passing silently. The alternative
146
- construction, `expect(props).to all match_schema(...)`, would pass on an empty
147
- array.
146
+ construction, `expect(props).to all match_ts_schema(...)`, would pass on an
147
+ empty array.
148
148
 
149
149
  ## API
150
150
 
151
- | Call | Returns |
152
- | --------------------------------------- | ----------------------------------------------------------- |
153
- | `TsSchemaSpec.schema_for(path, type)` | a `JSONSchemer` schema scoped to that exported type |
154
- | `match_schema(path, type)` | matcher; validates a hash, or every item of an array |
155
- | `react_component_props(name[, html])` | array of props hashes, one per mount |
156
- | `TsSchemaSpec::Skill.check!(root)` | raises if the installed skill is stale or missing |
157
- | `TsSchemaSpec.configure` | sets `tsconfig` and extra generator arguments |
158
- | `TsSchemaSpec.clear_cache!` | drops the generated-schema cache |
151
+ | Call | Returns |
152
+ | ------------------------------------- | ---------------------------------------------------- |
153
+ | `TsSchemaSpec.schema_for(path, type)` | a `JSONSchemer` schema scoped to that exported type |
154
+ | `match_ts_schema(path, type)` | matcher; validates a hash, or every item of an array |
155
+ | `react_component_props(name[, html])` | array of props hashes, one per mount |
156
+ | `TsSchemaSpec::Skill.check!(root)` | raises if the installed skill is stale or missing |
157
+ | `TsSchemaSpec.configure` | sets `tsconfig` and extra generator arguments |
158
+ | `TsSchemaSpec.clear_cache!` | drops the generated-schema cache |
159
+
160
+ `match_ts_schema` was called `match_schema` before 0.6.1. The old name still
161
+ works but is deprecated and will be removed.
159
162
 
160
163
  `path` is resolved from wherever the suite runs, which is the Rails root in
161
164
  practice. Name the type at the assertion, so an example says which type it is
@@ -208,8 +211,8 @@ generator, a shared JSON file, whatever suits your repo. That is outside this
208
211
  gem's scope, but with one in place, and a record for each value in the
209
212
  example, a drifted union fails here rather than in the browser.
210
213
 
211
- **Pass the whole collection.** `match_schema` validates every item and fails
212
- on an empty one. Avoid `expect(props).to all match_schema(...)`, which
214
+ **Pass the whole collection.** `match_ts_schema` validates every item and fails
215
+ on an empty one. Avoid `expect(props).to all match_ts_schema(...)`, which
213
216
  passes on an empty array, hiding an issue with generation.
214
217
 
215
218
  **Assert the response is successful first.** Otherwise a redirect or a 500
@@ -243,14 +246,14 @@ The cache lives in the process, so parallel test workers each pay for it once.
243
246
 
244
247
  ## Troubleshooting
245
248
 
246
- | Symptom | Cause |
247
- | ---------------------------------------------------- | -------------------------------------------------------------- |
248
- | `GenerationError: ... Is it exported?` | the type has no `export`, or the name is misspelled |
249
- | `GenerationError` listing a rerunnable command | run it — the generator's own stderr is in the message |
250
- | passes against an obviously wrong payload | the type is all-optional, or an unresolved import became `{}` |
251
- | `could not run npx ts-json-schema-generator` | the generator is not in your `node_modules` |
252
- | `disallowed additional property` | see above — the payload sends what TypeScript does not declare |
253
- | `has no data-react-props attribute` | hand-written markup, or a mount from another integration |
249
+ | Symptom | Cause |
250
+ | ---------------------------------------------- | -------------------------------------------------------------- |
251
+ | `GenerationError: ... Is it exported?` | the type has no `export`, or the name is misspelled |
252
+ | `GenerationError` listing a rerunnable command | run it — the generator's own stderr is in the message |
253
+ | passes against an obviously wrong payload | the type is all-optional, or an unresolved import became `{}` |
254
+ | `could not run npx ts-json-schema-generator` | the generator is not in your `node_modules` |
255
+ | `disallowed additional property` | see above — the payload sends what TypeScript does not declare |
256
+ | `has no data-react-props attribute` | hand-written markup, or a mount from another integration |
254
257
 
255
258
  ## What this can't catch
256
259
 
@@ -260,7 +263,7 @@ Worth knowing before you rely on it.
260
263
  a spec for; an uncovered endpoint is exactly as exposed as before. That is what
261
264
  the skill is for, and it is convention rather than enforcement.
262
265
 
263
- **It only checks what TypeScript declares.** If Rails *intends* to send a field
266
+ **It only checks what TypeScript declares.** If Rails _intends_ to send a field
264
267
  nobody typed — say `as_json(only:)` carrying a misspelled attribute, which
265
268
  Rails drops silently — no generated schema requires it, so nothing fails. A
266
269
  structured serializer catches that class of mistake; this does not.
@@ -66,7 +66,7 @@ module TsSchemaSpec
66
66
  end
67
67
  end
68
68
 
69
- RSpec::Matchers.define :match_schema do |source, type|
69
+ RSpec::Matchers.define :match_ts_schema do |source, type|
70
70
  def validation_errors(actual, source, type)
71
71
  schema = TsSchemaSpec.schema_for(source, type)
72
72
  @errors = TsSchemaSpec::Matching.errors(schema, actual)
@@ -81,7 +81,7 @@ RSpec::Matchers.define :match_schema do |source, type|
81
81
 
82
82
  Usually the component was not rendered on the page, or no records
83
83
  existed for the endpoint to serialize. If an empty result is what you
84
- meant to assert, use `be_empty` or `eq([])` — match_schema on an empty
84
+ meant to assert, use `be_empty` or `eq([])` — match_ts_schema on an empty
85
85
  collection checks nothing.
86
86
  MSG
87
87
  end
@@ -121,3 +121,12 @@ RSpec::Matchers.define :match_schema do |source, type|
121
121
  "expected the payload not to match #{type} (#{source}), but it did:\n#{JSON.pretty_generate(actual)}"
122
122
  end
123
123
  end
124
+
125
+ module RSpec
126
+ module Matchers
127
+ def match_schema(...)
128
+ RSpec.deprecate("match_schema", replacement: "match_ts_schema")
129
+ match_ts_schema(...)
130
+ end
131
+ end
132
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TsSchemaSpec
4
- VERSION = "0.6.0"
4
+ VERSION = "0.6.2"
5
5
  end
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: ts-schema-spec
3
3
  description: >
4
- Write or update RSpec tests that use match_schema to verify a Rails
4
+ Write or update RSpec tests that use match_ts_schema to verify a Rails
5
5
  endpoint's payload matches the TypeScript type that consumes it. TRIGGER
6
6
  automatically (without being asked) whenever data crossing from Ruby to
7
7
  TypeScript is added or changed: adding a controller action; changing
@@ -9,7 +9,7 @@ description: >
9
9
  associations); adding or renaming a key in a render json: response or in
10
10
  props handed to a component; converting a Rails-mounted component from .jsx
11
11
  to .tsx; deleting a component's propTypes; or rendering an already-typed
12
- component from an action that has no match_schema spec. React is the common
12
+ component from an action that has no match_ts_schema spec. React is the common
13
13
  case, not a requirement — a Stimulus controller or a plain fetch client
14
14
  reading the payload counts the same. Invoked as /ts-schema-spec.
15
15
  ---
@@ -19,15 +19,15 @@ something changes, and including where there is no Ruby diff at all. Two rules
19
19
  keep that from multiplying:
20
20
 
21
21
  - **Repeated mounts of one component are a single example.**
22
- `react_component_props` returns every mount and `match_schema` checks each.
22
+ `react_component_props` returns every mount and `match_ts_schema` checks each.
23
23
  - **Assert on the component Rails mounts.** A child receiving props from its
24
24
  parent is covered transitively; use the parent's props type.
25
25
 
26
26
  ## Step 0 — Already covered?
27
27
 
28
- Covered = the spec for **the action rendering it** has a `match_schema` example
29
- on that component. A sibling component, or the same component from another
30
- action, is not coverage. Covered → stop.
28
+ Covered = the spec for **the action rendering it** has a `match_ts_schema`
29
+ example on that component. A sibling component, or the same component from
30
+ another action, is not coverage. Covered → stop.
31
31
 
32
32
  ## Step 1 — Find the TypeScript consumer
33
33
 
@@ -65,13 +65,13 @@ implying the spec covers them.
65
65
 
66
66
  ## Step 4 — Write the test
67
67
 
68
- | Action | Data source |
69
- | ------ | ----------- |
70
- | `render json:` | `response.parsed_body["key"]` |
68
+ | Action | Data source |
69
+ | ----------------- | ---------------------------------------- |
70
+ | `render json:` | `response.parsed_body["key"]` |
71
71
  | `react_component` | `react_component_props("ComponentName")` |
72
72
 
73
73
  `react_component_props` returns **an array**, one entry per mount, and needs
74
- `render_views`. Pass it straight to `match_schema`: it validates every entry
74
+ `render_views`. Pass it straight to `match_ts_schema`: it validates every entry
75
75
  and fails on an empty collection. Never wrap it in `all`, which iterates zero
76
76
  times on an empty array and asserts nothing.
77
77
 
@@ -87,7 +87,7 @@ describe "the props handed to MyComponent" do
87
87
 
88
88
  expect(response).to be_successful
89
89
  props = react_component_props("MyComponent")
90
- expect(props).to match_schema("app/javascript/MyComponent.tsx", "MyComponentProps")
90
+ expect(props).to match_ts_schema("app/javascript/MyComponent.tsx", "MyComponentProps")
91
91
  end
92
92
  end
93
93
  ```
@@ -100,12 +100,12 @@ Rules:
100
100
  - Build multiple records with different traits, so optional fields, enum values
101
101
  and nil associations are actually exercised. Use existing factory traits.
102
102
  - Assert `response` is successful before asserting shape.
103
- - Let `match_schema` do the shape checking; no hand-written field assertions.
103
+ - Let `match_ts_schema` do the shape checking; no hand-written field assertions.
104
104
  - Several components in one action: an example each, or one example marked
105
105
  `:aggregate_failures` if rendering the page is expensive — without it the
106
106
  first mismatch hides the rest.
107
107
  - Do not write a spec that only checks `response.status`, and do not duplicate
108
- an existing `match_schema` for the same action.
108
+ an existing `match_ts_schema` for the same action.
109
109
  - **When it fails, fix Rails.** The type is the consumer's contract: if the
110
110
  component needs a field, the payload is wrong. Loosening the type is always
111
111
  the quicker route to green, and it is how this stops catching anything.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ts_schema_spec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.6.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vernon Coffey