Skip to content

Test data with test:given ​

Task: test a page that depends on data and on who is looking — without a fixtures file and without a password.

The page lists the signed-in user's open tasks:

yaml
# Recipe: test data with test:given, and a signed-in user with test:as.
paths:
  components: ./components
  migrations: ./migrations

datasources:
  db:
    driver: sqlite
    database: ./data/tasks.db
sql
CREATE TABLE tasks (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    owner TEXT NOT NULL,
    title TEXT NOT NULL,
    done INTEGER NOT NULL DEFAULT 0 CHECK (done IN (0, 1))
);
xml
<q:component name="MyTasks" require_auth="true">
  <q:query name="mine" datasource="db">
    SELECT title FROM tasks WHERE owner = :me AND done = 0 ORDER BY id
    <q:param name="me" value="{session.userName}" type="string" />
  </q:query>

  <h1>{session.userName}'s open tasks</h1>
  <q:if condition="mine_result.recordCount == 0">
    <p>Nothing to do.</p>
  </q:if>
  <ul>
    <q:loop query="mine"><li>{mine.title}</li></q:loop>
  </ul>
</q:component>

Each test starts from an empty database built by migrations/. test:given puts in the rows the test needs — through the schema's rules, so a row the app could never have written (a done outside CHECK (… IN …), a missing required column it cannot fill) fails the step instead of slipping in. test:as signs a user in the way a login does:

xml
<q:test name="a user sees only their own open tasks" page="/">
  <test:given table="tasks" owner="Ana" title="Write the report" />
  <test:given table="tasks" owner="Ana" title="Old task" done="1" />
  <test:given table="tasks" owner="Bruno" title="Fix the printer" />
  <test:as user="Ana" />
  <test:visit />
  <test:expect status="200" text="Ana's open tasks" />
  <test:expect text="Write the report" />
  <test:expect no-text="Old task" />
  <test:expect no-text="Fix the printer" />
</q:test>

<q:test name="a user with nothing open is told so" page="/">
  <test:given table="tasks" owner="Bruno" title="Fix the printer" />
  <test:as user="Ana" />
  <test:visit />
  <test:expect text="Nothing to do." />
</q:test>

<q:test name="the page needs a signed-in user" page="/">
  <test:visit />
  <test:expect status="302" />
</q:test>
text
tests/tasks.test.q
  PASS  a user sees only their own open tasks
  PASS  a user with nothing open is told so
  PASS  the page needs a signed-in user
3 passed, 0 failed

no-text checks what must not be on the page — here, another user's task and a finished one. The whole vocabulary is in the Testing an App guide.

Tested: this page imports the files of examples/cookbook/testing/test-data/, and the result above is the report of running them.

MIT Licensed · Built with VitePress