Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions src/pages/ModelChooser.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,10 @@ const PATHS: { clicks: RegExp[]; id: string; model: string; code: string; lesson
{ clicks: [/middle step, or/i, /^an effect through a middle step$/i], id: 'mediation', model: 'Mediation model', code: 'indirect := a * b', lessonId: '17-1' },
{ clicks: [/middle step, or/i, /hang together/i], id: 'scale-reliability', model: "Scale reliability (Cronbach's alpha)", code: 'psych::alpha(items)', lessonId: '03-4' },
{ clicks: [/summing up/i, /traits behind them/i], id: 'exploratory-factors', model: 'Exploratory factor analysis (EFA)', code: 'factanal(', lessonId: '17-2' },
{ clicks: [...YES_NO, /a cross-table/i], id: 'cross-table', model: 'Chi-square test of independence', code: 'chisq.test(', lessonId: '09-3' },
{ clicks: [...YES_NO, /one percentage/i], id: 'proportion-vs-value', model: 'Exact binomial test', code: 'binom.test(', lessonId: '09-1' },
{ clicks: [TO_OUTCOME, /no order/i, /linked to one other category/i], id: 'cross-table', model: 'Chi-square test of independence', code: 'chisq.test(', lessonId: '09-3' },
{ clicks: [TO_OUTCOME, /ordered levels/i, /groups differ, or/i], id: 'rank-tests', model: 'Rank-based tests', code: 'kruskal.test(wellbeing ~ department, data = d)', lessonId: '12-4' },
{ clicks: [...YES_NO, /a cross-table/i], id: 'cross-table', model: 'Traditional chi-square test of independence', code: 'chisq.test(', lessonId: '09-3' },
{ clicks: [...YES_NO, /one percentage/i], id: 'proportion-vs-value', model: 'Traditional exact binomial test', code: 'binom.test(', lessonId: '09-1' },
{ clicks: [TO_OUTCOME, /no order/i, /linked to one other category/i], id: 'cross-table', model: 'Traditional chi-square test of independence', code: 'chisq.test(', lessonId: '09-3' },
{ clicks: [TO_OUTCOME, /ordered levels/i, /groups differ, or/i], id: 'rank-tests', model: 'Traditional rank-based tests', code: 'kruskal.test(wellbeing ~ department, data = d)', lessonId: '12-4' },
{ clicks: [BAYES, /your own priors/i], id: 'bayesian-regression', model: 'Bayesian linear regression (brms)', code: 'brm(', lessonId: '16-4' },
];

Expand Down Expand Up @@ -153,11 +153,11 @@ describe('ModelChooser', () => {
test('the traditional name is shown only when the leaf has one', async () => {
renderChooser();
await clickThrough([...GROUPS, /^two groups$/i]);
expect(screen.getByText('Traditional name:')).toBeTruthy();
expect(screen.getByText('Traditional counterpart:')).toBeTruthy();

await userEvent.click(screen.getByRole('button', { name: /start over/i }));
await clickThrough([...NUMERIC, /several predictors/i]);
expect(screen.queryByText('Traditional name:')).toBeNull();
expect(screen.queryByText('Traditional counterpart:')).toBeNull();
});

test('every node in the tree is well formed', () => {
Expand Down Expand Up @@ -294,7 +294,7 @@ describe('links and the index', () => {
await userEvent.type(search, 'kruskal');
expect([...index.querySelectorAll('.model-card button')].map((button) => button.textContent)).toEqual([
'Linear model with a categorical predictor',
'Rank-based tests',
'Traditional rank-based tests',
]);

await userEvent.clear(search);
Expand Down
10 changes: 5 additions & 5 deletions src/pages/ModelChooser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ function AnswerCard({ answer }: { answer: Answer }) {
</p>
{answer.traditional && (
<p>
<strong>Traditional name:</strong> {answer.traditional}
<strong>Traditional counterpart:</strong> {answer.traditional}
</p>
)}
<p>
Expand Down Expand Up @@ -159,7 +159,7 @@ function Index({ onPick }: { onPick: (id: string) => void }) {
<section className="model-index" aria-labelledby="model-index-title">
<div className="model-index-head">
<h2 id="model-index-title">Browse all {entries.length} models</h2>
<p>Already know what you need? Search by name, or by the test you know it as.</p>
<p>Already know what you need? Search by name, or by the traditional test you know it as.</p>
</div>
<div className="model-index-tools">
<label className="model-index-search">
Expand All @@ -168,7 +168,7 @@ function Index({ onPick }: { onPick: (id: string) => void }) {
<circle cx="8.5" cy="8.5" r="5.5" fill="none" stroke="currentColor" strokeWidth="2" />
<path d="M13 13l4.5 4.5" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
</svg>
<input type="search" value={query} onChange={(event) => setQuery(event.target.value)} placeholder="Search, for example t-test or mediation" />
<input type="search" value={query} onChange={(event) => setQuery(event.target.value)} placeholder="Search, for example mediation or a traditional test" />
</label>
<div className="model-index-filters" role="group" aria-label="Show">
{FILTERS.map((option) => (
Expand Down Expand Up @@ -498,8 +498,8 @@ export default function ModelChooser() {

<p className="model-chooser-legend">
Most snippets run as they are in the <Link to="/workspace">R Workspace</Link>, and the ones that need RStudio say so.
Each reads workplace.csv or wellbeing-population.csv, the course data the workspace already has, or a dataset built
into R when the course data has nothing that fits. For your own data, change the file name in read.csv() and the
Each reads workplace.csv or wellbeing-population.csv, the course data the workspace already has, or a dataset that
comes with R or with the package the snippet uses, when the course data has nothing that fits. For your own data, change the file name in read.csv() and the
column names.
</p>
</section>
Expand Down
11 changes: 6 additions & 5 deletions src/pages/SampleSize.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@ describe('sample size page', () => {
expect(question()).toBe('The sample you need');
// pwr.t.test(d = 0.3, power = 0.8) gives n = 175.4 per group.
expect(report()).toContain('352 participants (176 per group)');
expect(report()).toContain('d = 0.30 with 80% power in a two-sided independent-samples t-test at α = .05');
expect(report()).toContain('d = 0.30 with 80% power in a two-sided test of the group difference (the traditional independent-samples t-test) at α = .05');
// 176 / 0.9 rounds up to 196 per group.
expect(report()).toContain('we will recruit 392 participants');
expect(screen.getByText(/pwr.t.test\(d = 0.3, sig.level = 0.05, power = 0.8/)).toBeTruthy();
expect(screen.getByText(/is the independent-samples t-test \(Lesson 12-1\)/)).toBeTruthy();
expect(screen.getByText(/is the same as the traditional independent-samples t-test \(Lesson 12-1\)/)).toBeTruthy();
expect(trail()).toEqual(['Compare two separate groups', 'Plan a new study', 'My own guess of the scores', 'd = 0.30', '80% power', 'α = .05', 'Two-sided', '10% dropout']);
});

Expand Down Expand Up @@ -214,8 +214,8 @@ describe('sample size page', () => {
expect(question()).toBe('How many people will you lose?');
await pick(/^None/);
// λ = N·f² with df2 = N − 2: 128 people, 64 per group.
expect(report()).toContain('128 participants (64 per group, each measured in both conditions) are needed to detect an effect of f = 0.25 (with a correlation of r = .50 between conditions)');
expect(report()).toContain('the F test for the interaction in a 2 × 2 mixed ANOVA');
expect(report()).toContain("128 participants (64 per group, each measured in both conditions) are needed to detect an effect of f = 0.25 (an f that already includes the correlation of r = .50 between conditions; in G*Power's repeated-measures procedures, with r = .50, this is f = 0.125)");
expect(report()).toContain('the F test for the interaction in a 2 × 2 mixed design, one factor between and one within people (a traditional mixed ANOVA)');
expect(trail()).toContain('One factor between, one within');
});

Expand All @@ -227,7 +227,7 @@ describe('sample size page', () => {
await pick(/Whether one factor's effect depends on the other/);
expect(question()).toBe('How big is the effect you want to be able to find?');
await pick(/Choose a size in plain words/);
const disappears = screen.getByRole('button', { name: /The effect disappears \(f = 0.13\)/ });
const disappears = screen.getByRole('button', { name: /The effect disappears \(f = 0.125\)/ });
expect(disappears.textContent).toContain('Recommended');
// f = 0.5 / 4 = 0.125: λ = N/64 reaches 80% power at 508 people (127 per cell), as in R.
expect(disappears.textContent).toContain('Needs about 508 people');
Expand All @@ -236,6 +236,7 @@ describe('sample size page', () => {
await pick(/α = \.05/);
await pick(/^None/);
expect(report()).toContain('508 participants (127 in each of the four cells)');
expect(report()).toContain('an effect of f = 0.125');
});

test("the browser's Back button goes back one question, keeping the answers", async () => {
Expand Down
Loading