From f05dd00c5532758db4e38d5855683abc1fcddf60 Mon Sep 17 00:00:00 2001 From: Firehose Bot Date: Wed, 18 Mar 2026 20:02:20 +0000 Subject: [PATCH] test writer skill Focuses on integration tests, but might be more reusable --- .pi/skills/test-writer/SKILL.md | 148 ++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 .pi/skills/test-writer/SKILL.md diff --git a/.pi/skills/test-writer/SKILL.md b/.pi/skills/test-writer/SKILL.md new file mode 100644 index 0000000..3f52057 --- /dev/null +++ b/.pi/skills/test-writer/SKILL.md @@ -0,0 +1,148 @@ +--- +name: test-writer +description: Writes tests following Elixir/Phoenix best practices. Ensures DRY tests with proper helper functions, no duplicated setup code, and correct parameter defaults. Use when writing or modifying tests. +--- + +# Test Writer Skill + +## Overview + +This skill provides guidelines for writing clean, maintainable Elixir/Phoenix tests following best practices. + +## Core Principles + +### 1. DRY Tests + +Avoid duplication by creating focused helper functions: + +**Bad:** +```elixir +test "GET /users returns index", %{conn: conn} do + conn = get(conn, "/users") + body = html_response(conn, 200) + assert body =~ "Users" +end + +test "GET /users/:id returns show", %{conn: conn} do + conn = get(conn, "/users/1") + body = html_response(conn, 200) + assert body =~ "User" +end +``` + +**Good:** +```elixir +defp goto_users_page(conn, suffix \\ ""), do: get(conn, "/users" <> suffix) + +test "GET /users returns index", %{conn: conn} do + conn = goto_users_page(conn) + assert html_response(conn, 200) =~ "Users" +end + +test "GET /users/:id returns show", %{conn: conn} do + conn = goto_users_page(conn, "/1") + assert html_response(conn, 200) =~ "User" +end +``` + + +### 2. Separate Helpers for Different Assertion Patterns + +Don't use conditionals in helpers to handle different cases: + +**Bad:** +```elixir +defp goto_users_page(conn, suffix \\ "", check_title \\ true) do + path = "/users" <> suffix + conn = get(conn, path) + body = html_response(conn, 200) + if check_title, do: assert body =~ "Users" + assert body =~ "AppLayout" + body +end +``` + +**Good:** +```elixir +defp goto_users_page(conn, suffix \\ "") do + path = "/users" <> suffix + conn = get(conn, path) + body = html_response(conn, 200) + assert body =~ "Users" + assert body =~ "AppLayout" + body +end + +defp goto_user_page(conn, suffix) do + path = "/users" <> suffix + conn = get(conn, path) + body = html_response(conn, 200) + assert body =~ "AppLayout" + body +end +``` + +## Test Structure + +### Context Block + +```elixir +describe "resource name" do + # Shared setup in context if needed + # test "scenario" do ... +end +``` + +### Value Aliasing + +Never reuse value names. Elixir is immutable, but value aliasing is confusing. Use unique, meaningful names for the left hand side of assignments. Or use pipes `|>` to eliminate the need for naming. + +```elixir +test "GET /users returns index", %{conn: conn} do + # don't reassign + response = get(conn, "/users") + # ... +end +``` + +## Common Patterns + +### HTML Pages with Layout + +```elixir +defp goto_resource_page(conn, suffix \\ ""), do: ... +# Asserts common layout elements and page-specific content +``` + +### API Endpoints + +```elixir +test "GET /api/resource returns JSON", %{conn: conn} do + conn = conn |> put_req_header("accept", "application/json") + conn = get(conn, "/api/resource") + response = json_response(conn, 200) + # Assert structure +end +``` + +### Error Handling + +```elixir +test "returns 404 for nonexistent", %{conn: conn} do + assert html_response(get(conn, "/nonexistent"), 404) +end +``` + +## Running Tests + +### One focused test file + +```bash +cd /path/to/app +mix test test/path/to_test.exs +``` + +### all tests +```bash +make test +```