Skip to content

Repository files navigation

This is a Next.js project bootstrapped with create-next-app.

Getting Started

First, run the development server:

npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev

Open http://localhost:3000 with your browser to see the result.

You can start editing the page by modifying app/page.tsx. The page auto-updates as you edit the file.

This project uses next/font to automatically optimize and load Geist, a new font family for Vercel.

Learn More

To learn more about Next.js, take a look at the following resources:

You can check out the Next.js GitHub repository - your feedback and contributions are welcome!

Deploy on Vercel

The easiest way to deploy your Next.js app is to use the Vercel Platform from the creators of Next.js.

Check out our Next.js deployment documentation for more details.

The workflow for a schema change

  • Modify your TypeScript schema in app/db/schema.ts
  • Run npx drizzle-kit generate to create a new migration file
  • Review the generated SQL to make sure it looks correct
  • Run npx drizzle-kit migrate to apply the migration to your database

Tricky migration

It is common to end up in a situation where the migration state gets out of sync with the actual database, for example if you manually modify the database, edit a migration file after it has been applied, or generate a migration and then change the schema again before applying it.

When things go wrong, you will typically see errors like "relation already exists" or "column does not exist" when running drizzle-kit migrate. This happens because Drizzle's migration tracker thinks the database is in one state, but the actual database is in another.

During development, when the database does not contain any important data, the simplest recovery strategy is to start fresh. You can do this in two steps:

First, remove Drizzle's migration tracking from the database and drop all the tables you have created:

DROP TABLE IF EXISTS drizzle.__drizzle_migrations CASCADE;
DROP TABLE IF EXISTS notes CASCADE;
DROP TABLE IF EXISTS users CASCADE;

Second, remove the local migration history so that Drizzle Kit forgets all previously generated migrations:

npx drizzle-kit drop

The command drizzle-kit drop lets you select which migration entries to remove from the local journal. After dropping them, you can regenerate and reapply everything cleanly:

npx drizzle-kit generate
npx drizzle-kit migrate

This "nuclear option" is perfectly fine during development. In production, however, you should never drop tables or delete migration history, since that means losing real user data. In a production environment, the correct approach is to always move forward: write a new migration that fixes the problem, rather than trying to undo previous ones.

Running tests

There are several things you should do to set up the tests for your project.

Changes in your submission repository

Copy the directories tests and .github from this repository to the root of your submission repository.

Replace the file drizzle.config.ts in your repository with the one you find in this directory.

Install the following:

npm install --save-dev @playwright/test dotenv
npx playwright install

Add scripts to package.json:

{
  // ...
  scripts:{
    "test:e2e": "playwright test",
    "test:e2e:ui": "playwright test --ui",
  }
}

Test DB and repository secrets

Create a new Neon DB in Vercel

Set up environment variables for your GitHub repository:

Click Settings → Secrets and variables → Actions

  • Add these repository secrets:
    • DATABASE_URL - Your Neon test database URL
    • NEXTAUTH_SECRET - any_random_character_sequence
    • NEXTAUTH_URL - Use http://localhost:3000

Create file .env.local to your submission repository with following

DATABASE_URL=your_neon_test_database_URL
NEXTAUTH_SECRET=any_random_character_sequence
NEXTAUTH_URL=http://localhost:3000

Running tests

You can run tests locally with npm run test:e2e

Assumptions that tests make

Tests are making several assumptions on your UI:

  • form controls must have labels "Username", "Password", "Title", etc.
  • urls: "login", "blogs", "me", etc.
  • test IDs

Eg. the below tests assumes that the url of the creation form is /blogs/new, form controls have the labels and eg. the creation button has test id create-blog-button:

test('logged in user can create a blog', async ({ page }) => {
  await loginUser(page, 'testuser', 'testpass123');

  await page.goto('/blogs/new');
  await page.getByLabel('Title', { exact: true }).fill('Test Blog');
  await page.getByLabel('Author', { exact: true }).fill('Test Author');
  await page.getByLabel('URL', { exact: true }).fill('http://testblog.com');
  await page.getByTestId('create-blog-button').click();

  // Should redirect to blogs page
  await expect(page).toHaveURL('/blogs');

  // Should show success notification
  await expect(page.getByTestId('notification')).toBeVisible();

  // Blog should appear in the list
  await expect(page.getByTestId('blogs-list')).toContainText('Test Blog');
});

The test id is added to the button with prop data-testid:

<button
  type="submit"
  data-testid="create-blog-button"
  className="w-full py-2 bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors font-semibold"
  {...props}
>
  Create
</button>

See the tests for more!

Tests in GitHub

Commit .github to your submission repository and push it to GitHub

Releases

Packages

Contributors

Languages