Need help? Join our Discord — ask questions, share projects, and connect with the Quill community.

Real-World Example: API Testing with Quill

This is a real test suite that validates the Trade Buddy marketplace API — a live production API for a student trading platform. Every test below is written entirely in Quill, demonstrating that readable code and powerful testing are not mutually exclusive.

38
Tests
215
Lines of Quill
~400
Equivalent lines of JavaScript

Setup and Configuration

The test suite starts by declaring the API base URL and defining reusable helper functions. In Quill, creating a variable is as simple as writing name is value, and functions are defined with the to keyword. No imports, no boilerplate, no semicolons.

-- Trade Buddy API Test Suite -- Run: quill test examples/tradebuddy-tests.quill api_url is "https://mytradebuddy.com/api" -- Helper Functions to isValidEmail addr: if addr contains "@" and addr contains ".": give back yes give back no to isValidCategory cat: valid are ["Electronics", "Books", "Video Games", "Toys", "Household Items", "Kitchen Items", "Furniture", "Sports Equipment", "Clothing & Accessories", "Jewelry & Watches", "Board Games", "School Uniform", "Stationery"] give back includes(valid, cat) to isValidType t: valid are ["Sell", "Donate", "Wanted"] give back includes(valid, t) to formatPrice amount: if amount is 0: give back "Free" give back "AED {amount}"

Quill Feature: English-Like Syntax

Notice how if addr contains "@" and addr contains "." reads like a sentence. Quill uses yes/no instead of true/false, give back instead of return, and is instead of =. The goal is code that anyone can read, even without programming experience.


Unit Tests for Helper Functions

Before testing the API, we validate our helper functions in isolation. Quill's test keyword creates a named test block, and expect asserts a condition. If any expectation fails, the test fails with a clear message.

test "isValidEmail accepts valid emails": expect isValidEmail("user@example.com") is yes expect isValidEmail("student@school.edu") is yes test "isValidEmail rejects invalid emails": expect isValidEmail("not-an-email") is no expect isValidEmail("missing-at.com") is no test "isValidCategory recognizes all categories": expect isValidCategory("Electronics") is yes expect isValidCategory("Books") is yes expect isValidCategory("Video Games") is yes test "isValidCategory rejects unknown categories": expect isValidCategory("Pets") is no expect isValidCategory("Cars") is no test "formatPrice shows Free for zero": expect formatPrice(0) is "Free" test "formatPrice formats non-zero amounts": expect formatPrice(25) is "AED 25" expect formatPrice(99.99) is "AED 99.99" test "countByType counts correctly": sample are [{type: "Sell"}, {type: "Donate"}, {type: "Sell"}] expect countByType(sample, "Sell") is 2 expect countByType(sample, "Donate") is 1 expect countByType(sample, "Wanted") is 0

Quill Feature: Built-In Testing

No test framework to install. No configuration files. Just write test "name": and expect value is expected. Run with quill test your-file.quill and you get clear pass/fail output.


Authentication Tests

These tests verify the login, signup, and logout endpoints. We check that invalid credentials return failures, missing fields are caught, and error responses have the expected shape. The await keyword handles async HTTP calls naturally.

test "login with invalid credentials returns failure": response is await postJSON("{api_url}/auth.php?action=login", {email: "fake@nonexistent.com", password: "wrongpassword123"}) expect response.success is no test "login with missing email returns failure": response is await postJSON("{api_url}/auth.php?action=login", {password: "test1234"}) expect response.success is no test "login error response contains error field": response is await postJSON("{api_url}/auth.php?action=login", {email: "fake@test.com", password: "wrong"}) expect response.success is no expect isText(response.error) is yes test "signup without name fails": response is await postJSON("{api_url}/auth.php?action=signup", {email: "test@example.com", password: "securepass"}) expect response.success is no test "signup without email fails": response is await postJSON("{api_url}/auth.php?action=signup", {name: "Test User", password: "securepass"}) expect response.success is no test "logout without token fails": response is await postJSON("{api_url}/auth.php?action=logout", {}) expect response.success is no

Quill Feature: Async Made Simple

Quill uses await to pause and wait for network requests, just like you would wait for a reply in a conversation. No .then() chains, no callback functions — just response is await postJSON(url, data).


Listings and Data Validation Tests

These tests fetch the public listings endpoint and verify that every listing has the correct fields, valid types and categories, and proper pricing. The for each loop checks every single listing in the response.

test "listings endpoint returns success": data is await fetchJSON("{api_url}/listings.php") expect data.success is yes test "each listing has a valid type": data is await fetchJSON("{api_url}/listings.php") for each item in data.listings: expect isValidType(item.type) is yes test "each listing has a valid category": data is await fetchJSON("{api_url}/listings.php") for each item in data.listings: expect isValidCategory(item.category) is yes test "sell listings have numeric prices": data is await fetchJSON("{api_url}/listings.php") sells is filter(data.listings, with i: i.type is "Sell") for each item in sells: expect isNumber(item.price) is yes expect item.price is greater than 0 test "each listing has a seller name": data is await fetchJSON("{api_url}/listings.php") for each item in data.listings: expect isText(item.sellerName) is yes expect length(item.sellerName) is greater than 0

Quill Feature: Lambdas with "with"

Filtering a list uses the with keyword: filter(listings, with i: i.type is "Sell"). It reads almost like English: "filter listings, with each item where the type is Sell." Compare that to JavaScript's listings.filter(i => i.type === "Sell").


Data Integrity Tests

Beyond checking individual fields, these tests verify the dataset as a whole: no duplicate IDs, non-empty titles, valid date formats, and no negative prices. These are the kinds of tests that catch real bugs in production data.

test "no duplicate listing IDs": data is await fetchJSON("{api_url}/listings.php") ids is map_list(data.listings, with i: i.id) expect length(unique(ids)) is length(ids) test "listing titles are non-empty strings": data is await fetchJSON("{api_url}/listings.php") for each item in data.listings: expect isText(item.title) is yes expect length(trim(item.title)) is greater than 0 test "listing prices are not negative": data is await fetchJSON("{api_url}/listings.php") for each item in data.listings: if isNumber(item.price): expect item.price is greater than -1

Response Shape Tests

API contract validation ensures the server always returns the JSON structure your application expects. These tests guard against breaking changes in the API by verifying fields, types, and the overall shape of every response.

test "listings response is a valid object": data is await fetchJSON("{api_url}/listings.php") expect isObject(data) is yes test "listings response has success field": data is await fetchJSON("{api_url}/listings.php") expect data.success is yes test "login error has correct JSON structure": response is await postJSON("{api_url}/auth.php?action=login", {email: "bad", password: "bad"}) expect isObject(response) is yes expect response.success is no expect isText(response.error) is yes test "listing objects have consistent shape": data is await fetchJSON("{api_url}/listings.php") if length(data.listings) is greater than 0: first is data.listings[0] expect isText(first.id) is yes expect isText(first.title) is yes expect isText(first.type) is yes expect isText(first.category) is yes expect isText(first.description) is yes expect isText(first.sellerName) is yes

Quill vs JavaScript: Side by Side

Here is the same logic written in both languages. Quill is designed to be immediately understandable, even to someone who has never programmed before.

Example 1: A simple test

Quill
test "login with bad creds fails": response is await postJSON(url, { email: "fake@test.com", password: "wrong" }) expect response.success is no
JavaScript (Jest)
test("login with bad creds fails", async () => { const response = await fetch(url, { method: "POST", headers: {"Content-Type": "application/json"}, body: JSON.stringify({ email: "fake@test.com", password: "wrong" }) }).then(r => r.json()); expect(response.success).toBe(false); });

Example 2: Validating a list

Quill
test "all types are valid": data is await fetchJSON(url) for each item in data.listings: expect isValidType(item.type) is yes
JavaScript (Jest)
test("all types are valid", async () => { const res = await fetch(url); const data = await res.json(); const valid = ["Sell", "Donate", "Wanted"]; data.listings.forEach(item => { expect(valid).toContain(item.type); }); });

Example 3: No duplicate IDs

Quill
test "no duplicate listing IDs": data is await fetchJSON(url) ids is map_list(data.listings, with i: i.id) expect length(unique(ids)) is length(ids)
JavaScript (Jest)
test("no duplicate listing IDs", async () => { const res = await fetch(url); const data = await res.json(); const ids = data.listings.map(i => i.id); const uniqueIds = [...new Set(ids)]; expect(uniqueIds.length).toBe(ids.length); });

Try It Yourself

Want to write code that reads like English? Open the Quill playground and start experimenting. No installation required.

Open the Playground

View on GitHub  ·  Join the Discord  ·  quill.tradebuddy.dev

Need help? Have questions?

Join the Trade Buddy Discord for help with Quill, API questions, and community support.

Join our Discord