惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
人人都是产品经理
人人都是产品经理
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
T
The Exploit Database - CXSecurity.com
N
News and Events Feed by Topic
Latest news
Latest news
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
CXSECURITY Database RSS Feed - CXSecurity.com
IT之家
IT之家
V
V2EX
WordPress大学
WordPress大学
Apple Machine Learning Research
Apple Machine Learning Research
Cisco Talos Blog
Cisco Talos Blog
K
Kaspersky official blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
S
SegmentFault 最新的问题
小众软件
小众软件
A
Arctic Wolf
酷 壳 – CoolShell
酷 壳 – CoolShell
腾讯CDC
宝玉的分享
宝玉的分享
Last Week in AI
Last Week in AI
G
GRAHAM CLULEY
罗磊的独立博客
T
Tor Project blog
C
Cisco Blogs
美团技术团队
博客园 - Franky
月光博客
月光博客
博客园 - 三生石上(FineUI控件)
T
Threat Research - Cisco Blogs
Cyberwarzone
Cyberwarzone
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
有赞技术团队
有赞技术团队
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Security Latest
Security Latest
博客园 - 司徒正美
Hugging Face - Blog
Hugging Face - Blog
Spread Privacy
Spread Privacy
J
Java Code Geeks
C
CERT Recently Published Vulnerability Notes
大猫的无限游戏
大猫的无限游戏
S
Securelist
The Cloudflare Blog
博客园 - 叶小钗
D
Darknet – Hacking Tools, Hacker News & Cyber Security
阮一峰的网络日志
阮一峰的网络日志
雷峰网
雷峰网
Project Zero
Project Zero

Railway Blog

Where Railway is, and where it's going (Summer 2026) PaaS vs IaaS vs SaaS: What Each Means and Who Should Pick What in 2026 The Best Continuous Deployment Tools in 2026 The Best PaaS for Multi-Region Deployments in 2026 The Best Platforms for Monorepo Deployments in 2026 Compliance Isn't a Feature, It's a Posture What is BYOC (Bring Your Own Cloud)? A Developer's Guide for 2026 The Best Managed Kubernetes Hosting in 2026 The Best Container Registries in 2026 The Vanilla Cloud Tax: What Rolling Your Own on AWS Actually Costs What is a PaaS? A Developer's Guide for 2026 The Best Cloud Observability and Logging Tools in 2026 The Best PostgreSQL Hosting for Developers in 2026 The Best Multi-Region Hosting Platforms in 2026 The Best Platforms to Deploy AI Apps in 2026 (Not the Models, the Apps Around Them) The Agent-Native Cloud: What It Means and Why It Matters Incident Report: May 19, 2026- GCP Account Suspension Counting to 3 with a new builder processing 50M+ monthly builds Railway iOS preview now available via TestFlight Kill your onboarding: selling to 10,000+ new users a day Your AI wants to nuke your database. Guardrails fix that. Better Rails for Agents: A New Remote MCP and Railway Agent in the CLI Moving Railway's Frontend Off Next.js One command deploys, there's a Stripe APP for that From registrar to deployed: buying a domain inside Railway A letter to open source builders who deserve more Networking is a black box, we used eBPF to open it Heroku Walked So Railway Can Run Security Features Your Security Team Will Love Railway Runs Open Source, Now We're Funding It Railway raises $100M Series B to unburden the builders Deploy autoscaling services, AI Workflow automation, and LLM APIs Without Kubernetes Hosting Postgres with GeoLite2: a practical guide to IP geolocation, data loading, and updates Serverless functions vs containers: CI/CD, database connections, cron jobs, and long-running tasks Hosting Postgres with pgvector: provider tradeoffs, migrations, indexes, and tuning Introducing the Railway integration on Delve.co Secure Cloud Hosting for Compliance: A Practical Guide for Startups and Regulated Industries How G2X Unlocked Rapid Experimentation at Scale with Railway MindFort Runs 100+ AI Pen Testing Agents Without Their Previous $10k AWS Bill How Bilt's Marketing Engineering Team Delivers at Scale with Railway Railway Technology Partners: Earn Revenue on Templates You Didn't Build ~$1 Million Paid to Developers Who Built Railway Templates CI/CD for Modern Deployment: From Manual Deploys to PR Environments Kernel Powers 1,000+ AI Agents on $444/Month of Railway Infrastructure Deploy Full-Stack TypeScript Apps: Architectures, Execution Models, and Deployment Choices Railway vs Cloudflare: How Their Architectures Differ and When to Use Each Run Scheduled and Recurring Tasks with Cron Monitoring & Observability: Using Logs, Metrics, Traces, and Alerts to Understand System Failures Logs, Metrics, and Traces: What Does Each Signal Tell You? Server rendering benchmarks: Railway vs Cloudflare vs Vercel Top five Heroku alternatives Comparing top PaaS and deployment providers Pricing to Encourage Use The F in SOC2 stands for functional Deploy Together, Earn Together: Introducing Railway Partnerships How We Oops-Proofed Infrastructure Deletion on Railway Bring Back the Free Plan Railway MCP - Stateful, Serverful, Pay-per-use Infrastructure Hackathon: Winners Announced! Mark Your Calendar: Railway User Hackathon with Prizes Launching Railway's Affiliate Program Zero-Touch Bare Metal at Scale Ssh, We’re Announcing One More Thing! $1M for Open Source Introducing Central Station Speed Isn’t Just About Code, It’s About Where That Code Runs One-Second Deploys? We Didn’t Believe It Either Why We’re Moving on From Nix Railway V3: Faster and Cheaper How to Migrate from Cloudflare Pages to Railway Supercharging Directus on Railway with a Static Frontend How to Migrate from AWS Lambda to Railway Deploy Triton Inference Server on Railway How to Handle Database Connection Pooling Building a NestJS App on Railway Manually Optimize Deployments on Railway Scaling a SaaS application on Railway Building a SaaS application on Railway Deploy a Dart App on Railway, Part 2 Deploy a Dart App on Railway, Part 1 Implementing Feature Flags from Scratch Cron Jobs with Django and GitHub Actions Deploy Offen on Railway Queues on Railway Working with NX, Railway and CI/CD Automated PostgreSQL Backups Using GitLab CI/CD with Railway Migrating From Heroku To Railway Cron Jobs on Railway Deploy Beam on Railway Deploy Authorizer on Railway Deploying Monorepo Applications How to Backup and Restore Your Postgres Database How to Backup Your Redis Instance Deploy Cusdis on Railway Deploy Ghost on Railway Using Github Actions with Railway Deploy Calendso (cal.com) on Railway Self-hosted website analytics Use Notion as a CMS for your NextJS blog
Implement a GitHub Actions Testing Suite
Carl Liu · 2024-12-13 · via Railway Blog

This tutorial will show you how to create a test suite for a codebase hosted in a GitHub repository. Using GitHub actions, you'll be able to -

  • Run the tests automatically when pull requests (PRs) are opened
  • Ensure that the tests still pass after merging
  • Put checks in place to ensure successful deployments

I've created an example repository on GitHub that you can clone and reference while going through the tutorial, linked here.

Intro to GitHub Actions

GitHub Actions are a way to execute software workflows which is deeply integrated with GitHub repositories. Using YAML, you can specify workflows, each of which can have multiple steps, that will run based on specific triggers, such as on pull requests, on pushes, and more.

There is also a marketplace for GitHub Actions where you can find and use Actions created by other users within your own workflows; many of these Actions are free to use.

Setting up our application

For our example project, let's create a simple web service that we can make API calls to using TypeScript and Fastify.

When our service receives a POST request, it will respond with what day of the week that date is on. For testing, we'll use Vitest; however, Jest and Mocha are popular alternatives you can consider. If you wanted to test a user interface (UI), Playwright and Cypress are options you could use for end-to-end and UI tests.

Railway has a template for deploying a Fastify application, so, to get started, all you have to do is:

  1. Go to the template's GitHub repository and click "Deploy on Railway"
  2. Login or sign up using your GitHub account or your email
  3. Eject from the template's GitHub repository so that you have your own copy to build off of and edit
Ejecting from template in service settings
Ejecting from template in service settings

Now, you have your own Fastify application that deploys from GitHub to Railway automatically! You can clone the new repository and start working on it from our machine.

Functionality

Let's create an API route for getting the weekday of a date. In the src/routes/root.ts file, you can add a Fastify route with the following code:

// src/routes/root.ts
import { FastifyInstance, FastifyPluginAsync } from "fastify";

const root: FastifyPluginAsync = async (fastify: FastifyInstance) => {
  // other template code...

  // new code
  fastify.get("/weekday", async (request, reply) => {
    const dateQuery: string | undefined = (request.query as any).date;
    if (!dateQuery) {
      return reply
        .code(400)
        .send({ error: "Date query parameter is required" });
    }
    const date = new Date(dateQuery);
    if (date.toString() === "Invalid Date") {
      return reply.code(400).send({ error: "Invalid date format" });
    }
    console.log(date);
    const weekdayIndex = date.getDay();
    const weekdays = [
      "Sunday",
      "Monday",
      "Tuesday",
      "Wednesday",
      "Thursday",
      "Friday",
      "Saturday",
    ];
    const weekday = weekdays[weekdayIndex];
    return reply.code(200).send({ weekday });
  });
};

export default root;

When you run our application locally with npm run dev, you'll be able to send requests to the API with this format:

curl "localhost:3000/weekday?date=$DATE"

The route will expect the date string in a query parameter. If you omit the query parameter or send an unparseable string, you'll get a 400 error code back. Otherwise, the JSON response body will contain the weekday of the date.

Testing

To set up testing, you can follow the steps from Vitest's getting started guide (https://vitest.dev/guide/) to initialize and configure your tests.

First, add Vitest as a depedency by running:

npm install -D vitest

Next, add an entry to the scripts section of your package.json file which will use Vitest when your run "test":

{
  "scripts": {
    "test": "vitest"
  }
}

Next, create a file for your tests called integration.test.ts. You can add a few tests for our API inside:

// integration.test.ts
import { expect, test } from "vitest";

test("returns correct weekday", async () => {
  const res = await fetch("http://localhost:3000/weekday?date=03/01/2023");
  const data = await res.json();
  expect(data.weekday).toBe("Wednesday");
});

test("rejects missing query parameter", async () => {
  const res = await fetch("http://localhost:3000/weekday");
  expect(res.status).toBe(400);
});

test("rejects unparseable date string", async () => {
  const res = await fetch("http://localhost:3000/weekday?date=foobar");
  expect(res.status).toBe(400);
});

Now, if you have the Fastify application running locally, you can run the tests with:

npm run test

Setting up your test suite

Now that you've set up testing and written our first tests, we can create the workflows for GitHub Actions to run. GitHub will look at the root of your repository for a .github/workflows/ folder. In that folder, you can create YAML files outlining the steps to your workflows. Each file can specify different triggers which would cause it to run.

First, create a YAML file at .github/workflows/tests.yaml.

Then, add the following to the top of the file:

name: tests

on:
  push:
    branches:
      - main
  pull_request:

This defines a workflow that will run whenever a pull request is opened and whenever a commit is pushed to main.

Next, you can specify the jobs that the workflow will run. You'll have one for running the tests with Vitest; it first checks out the repository, then sets up node so that you have access to npm, and then it installs, builds, and runs the app before running the tests:

name: tests

on:
  push:
    branches:
      - main
  pull_request:

jobs:
  vitest:
    name: API Tests
    runs-on: ubuntu-latest
    steps:
    - name: Checkout repository
      uses: actions/checkout@v4
    - uses: actions/setup-node@v4
      with:
        node-version: "22"
    - name: Install deps
      run: npm install
    - name: Build app
      run: npm run build
    - name: Run app
      run: RUNNER_TRACKING_ID="" && (nohup npm run start &) # this starts the app in the background
    - name: Run tests
      run: npm run test

If we want to make sure that the tests pass before being able to merge pull requests, you can create a branch ruleset on the repository:

Creating a new ruleset in GitHub
Creating a new ruleset in GitHub

You turn on enforcement and specify who can bypass the rules:

Configuring the branch ruleset in GitHub
Configuring the branch ruleset in GitHub

And you can also specify which branches you want this rule to apply to:

Adding a branch target in GitHub
Adding a branch target in GitHub

There are a number of rules that you can read about below. The one we're interested in is "Require status checks to pass":

Setting require status checks to pass
Setting require status checks to pass

To add the tests as a requirement before merging, just type in their name (API Tests):

Adding the API Tests as required checks
Adding the API Tests as required checks

Now, pull requests cannot be merged unless the tests are passing (unless you are an admin or on the bypass list, in which case you can bypass the checks and merge PRs anyways).

Updating your service

Now that we're finished with the workflow, let's try making a change to the app. Create a new branch by running:

git checkout -b $BRANCH_NAME

and:

git push -u origin $BRANCH_NAME

In src/routes/root.ts, let's imagine that while we're making changes, we make a typo and accidentally change the route path to "wekday":

// src/routes/root.ts
// ...
const root: FastifyPluginAsync = async (fastify: FastifyInstance) => {
  // ...
  fastify.get("/wekday", async (request, reply) => {
    // ...
  });
};

export default root;

Let's open a pull request from the new branch to main. At the bottom of the pull request's page, you'll see that merging is blocked due to the tests failing:

Demonstrating tests failing in GitHub
Demonstrating tests failing in GitHub

GitHub will even send us an email to let us know that our workflow run has failed:

Email notification about failed test from GitHub
Email notification about failed test from GitHub

It's great that the tests are catching our mistakes on pull requests, but it's also wise to make sure bad merges don't get deployed. Since the tests run when pull requests are also merged to main, you can configure Railway to wait until tests are passing before auto-deploying. In the Railway project that's been deployed, you can go to the settings for your "server" service and enable that setting:

Configuring Railway to wait for ci
Configuring Railway to wait for ci

What happens as your codebase grows

We now have a test suite set up via GitHub Actions that will let us know if tests are failing before we merge pull requests or deploy our code!

This example project is fairly simple, but GitHub Actions has many advanced features that come in handy as your project grows. For example: