Skip to content

Commit 635a745

Browse files
committed
fix(tarot-spread): title from the response, so a yes or no cast is not headed three card
1 parent 47d29f2 commit 635a745

2 files changed

Lines changed: 71 additions & 4 deletions

File tree

packages/ui/src/components/tarot-spread.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ type TarotSpreadData =
2727
* Tarot spread card. Renders /tarot/spreads/{three-card,celtic-cross,love},
2828
* /tarot/yes-no, /tarot/draw responses.
2929
*/
30+
/** "three card" -> "Three card". Spread names arrive lowercase from both the API and the attribute, and a heading should not. */
31+
function titleCase(v: string): string {
32+
return v ? v.charAt(0).toUpperCase() + v.slice(1) : v;
33+
}
34+
3035
@customElement('roxy-tarot-spread')
3136
export class RoxyTarotSpread extends RoxyDataElement<TarotSpreadData> {
3237
static styles = [
@@ -203,10 +208,19 @@ export class RoxyTarotSpread extends RoxyDataElement<TarotSpreadData> {
203208
const answer = isYesNo ? (d as CastYesNoResponse).answer : undefined;
204209
const strength = isYesNo ? (d as CastYesNoResponse).strength : undefined;
205210
const verdictCard = isYesNo ? (d as CastYesNoResponse).card : undefined;
206-
const spreadLabel =
207-
'spread' in d
208-
? (d as CastThreeCardResponse).spread
209-
: this.spread.replace(/-/g, ' ');
211+
// Title from the RESPONSE SHAPE first, the attribute only as a last resort.
212+
// The API sends `spread: null` on several casts, and a host that cannot set
213+
// attributes (the WordPress plugin maps an operationId to a bare tag) always
214+
// falls through to the property default, so a yes or no reading was headed
215+
// "three card". Reading the shape means the heading is right either way.
216+
const spreadLabel = isYesNo
217+
? 'Yes or no'
218+
: isDrawn
219+
? 'Card draw'
220+
: titleCase(
221+
('spread' in d ? (d as CastThreeCardResponse).spread : '') ||
222+
this.spread.replace(/-/g, ' '),
223+
);
210224
const question =
211225
'question' in d ? (d as CastThreeCardResponse).question : undefined;
212226
const summary =

packages/ui/tests/components.test.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2158,3 +2158,56 @@ describe('roxy-dasha-timeline heads correctly with no period attribute', () => {
21582158
el.remove();
21592159
});
21602160
});
2161+
2162+
/**
2163+
* Tarot spread heading. Same failure class as the dasha timeline: the label used
2164+
* to come from the `spread` ATTRIBUTE, whose default is `three-card`, so a host
2165+
* that cannot set attributes (the WordPress plugin) headed every reading "three
2166+
* card" including a yes or no cast. The API also sends `spread: null` on several
2167+
* casts, so the response field alone is not enough either.
2168+
*/
2169+
describe('roxy-tarot-spread titles itself from the response', () => {
2170+
async function mount(data: unknown) {
2171+
const el = document.createElement('roxy-tarot-spread') as HTMLElement & {
2172+
data?: unknown;
2173+
};
2174+
document.body.appendChild(el);
2175+
el.data = data;
2176+
await settled(el);
2177+
return el;
2178+
}
2179+
const title = (el: Element) =>
2180+
el.shadowRoot?.querySelector('.title')?.textContent?.trim() ?? '';
2181+
2182+
test('a yes or no cast is not headed "three card"', async () => {
2183+
const el = await mount({
2184+
question: 'Should I take the new job',
2185+
answer: 'Yes',
2186+
strength: 'Strong',
2187+
spread: null,
2188+
card: { name: 'The Star', orientation: 'upright' },
2189+
});
2190+
expect(title(el)).toBe('Yes or no');
2191+
el.remove();
2192+
});
2193+
2194+
test('a named spread is used and capitalised', async () => {
2195+
const el = await mount({
2196+
spread: 'celtic cross',
2197+
question: 'What about work',
2198+
positions: [{ position: 'Present', card: { name: 'The Star' } }],
2199+
});
2200+
expect(title(el)).toBe('Celtic cross');
2201+
el.remove();
2202+
});
2203+
2204+
test('a null spread falls back without rendering an empty heading', async () => {
2205+
const el = await mount({
2206+
spread: null,
2207+
question: 'What about work',
2208+
positions: [{ position: 'Present', card: { name: 'The Star' } }],
2209+
});
2210+
expect(title(el)).toBe('Three card');
2211+
el.remove();
2212+
});
2213+
});

0 commit comments

Comments
 (0)