Skip to content

Split specs into per-class unit specs and integration specs - #188

Merged
satoryu merged 1 commit into
masterfrom
split-specs-per-class
Oct 17, 2026
Merged

satoryu merged 1 commit into
masterfrom
split-specs-per-class

Conversation

@satoryu

@satoryu satoryu commented Oct 17, 2026 •

Copy link
Copy Markdown
Member

Why

Most behavior was only tested through Docx::Document and real .docx fixtures. That works as an end-to-end test, but it means a failure doesn't point at the class that broke, and element behavior can't be tested without crafting a fixture.

What

The suite now mirrors lib/, one spec per class, in three layers:

Layer Location How
Unit spec/docx/containers/*, spec/docx/elements/*, spec/docx/helpers_spec.rb Nodes come from WordprocessingML fragments (w_node / w_body in spec/support/xml_helpers.rb). document_properties is passed as a plain hash, and the Document is an instance_double.
Document spec/docx/document_spec.rb Only what Document owns: opening the package, loading parts (styles, rels, headers, footers), document-wide lookups, and save / stream / replace_entry.
Integration spec/integration/* End-to-end scenarios on real fixtures: save-and-reopen round trips, plus regressions that depend on a real file's structure (Google Docs bookmarks, split placeholders, …).

Housekeeping:

  • spec_helper now loads docx/document. lib/docx.rb only autoloads Document, so style_spec worked only when it happened to run after document_spec.
  • Saved files go to a per-example temp dir (tmp_path) instead of spec/fixtures.
  • The no_styles font_size check was inside the 'reading' shared examples and described as "should raise an error" while asserting nil. It moved to Document#font_size.
  • Removed an empty example and a duplicated example name.
  • Updated the tdd-development skill and CLAUDE.md with where new tests go.

No library code changes.

Verification

  • 164 → 266 examples, all green across several random seeds.
  • Line coverage went from 96.36% to 98.92%. No line that was covered before is uncovered now.
  • Mutation check: I broke 12 representative spots in lib/ (substitute search offset, html alignment/size/strike, cell → paragraph property passing, column indexing, block-bookmark pPr handling, html_tag, style_of lookup, inspect truncation, left alignment). The unit specs alone catch every one.

Bugs found while writing unit specs (not fixed here)

These are behavior changes, so each is tracked as its own issue and will get a test-first PR:

  1. Element#prepend_to always raises NoMethodError #189 Element#prepend_to calls element.node.properties, which doesn't exist on Nokogiri nodes, so the method always raises.
  2. TextRun#text= on a run without w:t leaves #text stale #190 TextRun#text= on a run with no w:t writes the XML, but #text still returns "" because @text_nodes isn't refreshed.
  3. SimpleInspect#inspect(true) raises ArgumentError #191 SimpleInspect#inspect(true) raises ArgumentError: the bare super forwards the argument to Object#inspect.
  4. Document without word/_rels/document.xml.rels raises NoMethodError on #paragraphs #192 If word/_rels/document.xml.rels is missing, load_rels rescues and leaves @rels nil, and then #hyperlinks (and so #paragraphs) raises NoMethodError.

🤖 Generated with Claude Code

Most behavior was only tested through Docx::Document and real .docx
fixtures. Restructure the suite so it mirrors lib/:

- spec/docx/containers, spec/docx/elements: unit specs per class that build
  nodes from WordprocessingML fragments (spec/support/xml_helpers.rb),
  pass document_properties as a hash and use instance_double for the
  Document.
- spec/docx/document_spec.rb: only what Document owns (opening the
  package, loading parts, document-wide lookups, save/stream).
- spec/integration: end-to-end scenarios on real fixtures, including
  save-and-reopen round trips.

Also: load docx/document in spec_helper so element classes can be
referenced directly, write saved files to a per-example temp dir instead
of spec/fixtures, move the misplaced no_styles font_size check out of
the 'reading' shared examples, and document the layout for contributors.

No library code changes. 164 -> 266 examples; line coverage
96.36% -> 98.92%.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant