Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add some basic tests with actions and pre-commit updates. #15

Merged
merged 4 commits into from
Nov 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 37 additions & 36 deletions .github/workflows/firebase-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,61 +4,62 @@ on:
push:
branches:
- main
paths:
- 'src/**' # Changes to the source code
- 'public/**' # Changes to the public folder
- 'firebase.json' # Changes to the Firebase configuration
- 'package.json' # Changes to the package.json file
- 'index.html' # Changes to the index.html file
- 'vitest.config.js' # Changes to the Vitest configuration
- '.firebaserc' # Changes to the Firebase configuration
- '.github/workflows/*' # Changes to the workflow file

concurrency:
group: firebase-deploy-${{ github.ref }}
cancel-in-progress: true

jobs:
# build:
# name: Build and Test
# runs-on: ubuntu-latest
build:
name: 🧱 Build and Test
runs-on: ubuntu-latest

steps:
- name: 📥 Checkout Code
uses: actions/checkout@v4

# steps:
# - name: Checkout Code
# uses: actions/checkout@v4
- name: 🛠️ Setup Node
uses: actions/setup-node@v4
with:
node-version: 'lts/*'
cache: 'npm'

# - name: Setup Node
# uses: actions/setup-node@v4
# with:
# node-version: 'lts/*'
- name: 📂 Install Packages
run: npm ci

# - name: Install Dependencies
# run: npm install
- name: 🧪 Run Tests with Vitest
run: npm run test:ci

# - name: Build Project
# run: npm run build
- name: 🔨 Build Project
run: npm run build

# - name: Run Tests
# run: npm test
deploy:
name: Deploy to Firebase
# needs: build
name: 🚀 Deploy to Firebase
needs: build # Only run this job if the build job is successful
runs-on: ubuntu-latest

steps:
- name: Checkout Code
- name: 📥 Checkout Code
uses: actions/checkout@v4

- name: Setup Node
- name: 🛠️ Setup Node
uses: actions/setup-node@v4
with:
node-version: 'lts/*'

- name: Cache dependencies 📦
uses: actions/cache@v4
with:
path: node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-

- name: Packages install
run: npm ci

- name: Build Project
run: npm run build

- name: Install Firebase Tools
- name: 🌍 Install Firebase Tools
run: npm install -g firebase-tools

- name: Deploy to Firebase
- name: 🚀 Deploy to Firebase
env:
FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
run: firebase deploy --token "${{ secrets.FIREBASE_TOKEN }}" --non-interactive
61 changes: 50 additions & 11 deletions .github/workflows/firebase-preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,45 +14,84 @@ jobs:
issues: write

steps:
- name: Checkout code
- name: 📥 Checkout code
uses: actions/checkout@v4

- name: Setup Node
- name: 📦 Setup Node
uses: actions/setup-node@v4
with:
node-version: 'lts/*'
cache: 'npm'

- name: Install dependencies
run: npm install
- name: 📂 Install dependencies
run: npm ci

- name: Build the app
- name: 🔨 Build the app
run: npm run build

- name: Install Firebase CLI
- name: 🧪 Test the app with Vitest
run: npm run test:ci | tee test-results.txt

# 🚮 Clean up test results for comment
- name: 🚮 Clean up test results
run: sed -i 's/\x1b\[[0-9;]*m//g' test-results.txt # Removes ANSI color codes

# 📄 Format test results for better readability
- name: 📄 Format test results
run: |
{
echo "### 🧪 Test Results"
echo ""
if grep -q "failed" test-results.txt; then
# Extract failed test details if any
echo "❌ **Some tests failed**:"
echo '```'
grep -E "Test Files|Tests|Duration|failed" test-results.txt
echo '```'
echo ""
echo "💥 Please review the failed tests above."
else
# Format output for passing tests
grep -E "(Test Files|Tests|Duration)" test-results.txt | while read -r line; do
if [[ $line == *"Test Files"* ]]; then
echo "🗂 **Test Summary**: $line"
elif [[ $line == *"Tests"* ]]; then
echo "✅ **Tests Passed**: $line"
elif [[ $line == *"Duration"* ]]; then
echo "⏱️ **Total Duration**: $line"
fi
done
echo ""
echo "🎉 All tests passed successfully!"
fi
} > formatted-results.txt

- name: 🚀 Install Firebase CLI
run: npm install -g firebase-tools

- name: Deploy to Firebase Preview Channel
- name: 🌐 Deploy to Firebase Preview Channel
id: firebase_deploy
env:
FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
run: |
firebase hosting:channel:deploy pr-${{ github.event.number }} --expires 2d | tee deploy-output.txt

- name: Extract Preview URL
- name: 🔗 Extract Preview URL
id: extract_url
run: |
# Find the actual preview URL from the Firebase deploy output
URL=$(grep -oP 'https:\/\/[^\s]+pr-${{ github.event.number }}[^\s]+' deploy-output.txt)
echo "PREVIEW_URL=${URL}" >> $GITHUB_ENV

- name: Post preview link to PR
- name: 💬 Post test results and preview link to PR
uses: actions/github-script@v7
with:
script: |
const previewUrl = process.env.PREVIEW_URL;
const fs = require('fs');
const testResults = fs.readFileSync('formatted-results.txt', 'utf8');
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `🚀 Preview for this PR is available at: ${previewUrl}`
body: `🚀 Preview for this PR is available at: ${previewUrl} \n\n ${testResults}`
});
17 changes: 14 additions & 3 deletions .github/workflows/label-pr-size.yml.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,22 @@ jobs:
runs-on: ubuntu-latest

steps:
- name: 🛎️ Checkout repository
uses: actions/checkout@v4

- name: Determine PR size and add label
id: size-label
uses: "pascalgn/[email protected].4"
uses: pascalgn/[email protected].5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
IGNORED: |
yarn.lock
package-lock.json
.pnp.*
dist/**
build/**
.cache/**

with:
sizes: >
{
Expand All @@ -43,7 +54,7 @@ jobs:
XXL: 'e99695', // Light coral
};

const sizeLabel = core.getInput('size-label-output') || '${{ steps.size-label.outputs.sizeLabel }}';
const sizeLabel = ${{ steps.size-label.outputs.sizeLabel }};
const color = labelsToColor[sizeLabel];

if (sizeLabel) {
Expand All @@ -66,7 +77,7 @@ jobs:
}

- name: Comment on large PRs
if: ${{ contains(steps.size-label.outputs.sizeLabel, 'XL') || contains(steps.size-label.outputs.sizeLabel, 'XXL') }}
if: ${{ contains(steps.size-label.outputs.sizeLabel, 'XL') }}
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
Expand Down
1 change: 1 addition & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
npx lint-staged
npm run test:ci
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"lint": "eslint src/**/*.{js,jsx}",
"lint:fix": "eslint src/**/*.{js,jsx} --fix",
"format": "prettier --write src/**/*.{js,jsx}",
"prepare": "husky"
"prepare": "husky",
"test:ci": "vitest run"
},
"lint-staged": {
"src/**/*.{js,jsx}": [
Expand Down
80 changes: 69 additions & 11 deletions src/App.test.jsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,76 @@
import { fireEvent, render, screen } from '@testing-library/react';
import { UserProvider } from '@contexts/UserContext';
import { act, fireEvent, render, screen, waitFor } from '@testing-library/react';
import { describe, expect, test } from 'vitest';

import App from './App';

describe('counter tests', () => {
test('Counter should be 0 at the start', () => {
render(<App />);
expect(screen.getByText('count is: 0')).toBeDefined();
describe('Check data before user logged in', () => {
test('Should show message when user is not logged in', async () => {
render(
<UserProvider>
<App />
</UserProvider>,
);

// Use `waitFor` to ensure the message appears after any async updates.
await waitFor(() => {
const message = screen.getByText('Please sign in to view this page');
expect(message).toBeTruthy();
});
});

test('Should redirect to Streak page when clicked on Streak tab', async () => {
render(
<UserProvider>
<App />
</UserProvider>,
);

// Wait for the loading spinner to disappear
await waitFor(() => {
expect(screen.queryByRole('progressbar')).toBeNull();
});

// Click the "Streak" tab
await act(async () => {
fireEvent.click(screen.getByText(/streak/i));
});

// Verify that the URL has changed to "/streak"
await waitFor(() => {
expect(window.location.pathname).to.equal('/streak');
});
});

test('Counter should increment by one when clicked', async () => {
render(<App />);
const counter = screen.getByRole('button');
fireEvent.click(counter);
expect(await screen.getByText('count is: 1')).toBeDefined();
test('Should able to redirect back to Home page from Streak page', async () => {
render(
<UserProvider>
<App />
</UserProvider>,
);

// Wait for the loading spinner to disappear
await waitFor(() => {
expect(screen.queryByRole('progressbar')).toBeNull();
});

// Click the "Streak" tab
await act(async () => {
fireEvent.click(screen.getByText(/streak/i));
});

// Verify that the URL has changed to "/streak"
await waitFor(() => {
expect(window.location.pathname).to.equal('/streak');
});

// Click the "Home" tab
await act(async () => {
fireEvent.click(screen.getByText(/home/i));
});

// Verify that the URL has changed to "/"
await waitFor(() => {
expect(window.location.pathname).to.equal('/');
});
});
});
52 changes: 52 additions & 0 deletions src/pages/Home.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { UserProvider } from '@contexts/UserContext';
import Home from '@pages/Home';
import { act, render, screen } from '@testing-library/react';
import { describe, expect, test, vi } from 'vitest';

// Mock `@contexts/UserContext` to control user profile and updates
vi.mock('@contexts/UserContext', async () => {
const actual = await vi.importActual('@contexts/UserContext');
let mockUserProfile = {
uid: '123',
profilePic: '',
name: 'Test User',
goals: [],
streak: [],
};

return {
...actual,
useUser: () => ({
user: mockUserProfile,
loading: false,
updateProfile: vi.fn((updates) => {
mockUserProfile = { ...mockUserProfile, ...updates };
}),
}),
};
});

describe('Home Screen - No Goals', () => {
beforeEach(() => {
// Reset mockUserProfile for each test
vi.clearAllMocks();
});

test('Displays only "New Goal" field when there are no goals', async () => {
await act(async () => {
render(
<UserProvider>
<Home />
</UserProvider>,
);
});

// Check if "New Goal" text field is present
const newGoalInput = screen.getByLabelText('New Goal');
expect(newGoalInput).not.to.be.null;

// Ensure "New Microgoal" and "New Task" fields are not present initially
expect(screen.queryByLabelText('New Microgoal')).to.be.null;
expect(screen.queryByLabelText('New Task')).to.be.null;
});
});
1 change: 1 addition & 0 deletions vite.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export default defineConfig({
},
test: {
globals: true,
reporters: process.env.GITHUB_ACTIONS ? ['dot', 'github-actions'] : ['dot'],
environment: 'jsdom',
},
});
Loading