Unit testing felt cumbersome while I was still figuring out the code structure of jsonapi-resources-anchor, so I ditched it.
I still wanted to test my code. But more integration-y.
For a gem that generates schema files, what could be more practical than snapshot testing?
I initially went with something like:
it 'should match snapshot' do
expect(generated_schema).to eq(File.read(path))
endWhen I was strictly refactoring code, it was great. Make changes, run tests, confirm there were no regressions. Repeat.
When I was expecting changes in the schema, it was less useful. I would regenerate the schema files with rails jsonapi:generate and check the git diff to see if I was happy with the results.
It left me wondering if an experience like Jest's interactive snapshot mode was possible, where you can interactively view diffs and accept them.
I recalled rails app:update had a similar experience for interactive merge conflict resolution, maybe I could use whatever powered that?
Yes, I could. It was rails/thor and it was surprisingly easy to integrate.
With Thor, we avoid the disjointed Rake task and git diff workflow.
This isn't to say the Rake task + git diff workflow no longer has utility. Sometimes, the diff is large and I want to view it outside of the merge conflict context, or even outside of the terminal. The Rake task + git diff workflow is more convenient in that case.
Demo and code using Thor below.
THOR_MERGE=nvim bundle exec rspecrequire "thor"
class SnapshotUpdate < Thor
include Thor::Actions
def self.prompt(...) = new.prompt(...)
desc "prompt", "Prompt user to update snapshot"
def prompt(...) = create_file(...)
end
RSpec.describe Anchor::TypeScript::SchemaGenerator do
it "generates correct schema" do
schema = described_class.call(register: Schema.register)
path = Rails.root.join("test/files", "schema.ts")
# if schema.ts doesn't exist, just write to it
File.open(path, "w") { |file| file.write(schema) } unless File.file?(path)
if ENV["THOR_MERGE"] && File.read(path) != schema
SnapshotUpdate.prompt(path, schema)
end
expect(File.read(path)).to eql(schema)
end
endNext step is to make this a custom RSpec matcher to have a more convenient API like expect(schema).to match_snapshot("schema.ts") in levinmr/rspec-snapshot.