Skip to content

Comments

Fix return type annotation in loadJWTKeys helper#558

Draft
Copilot wants to merge 10 commits intomasterfrom
copilot/add-jwt-tests
Draft

Fix return type annotation in loadJWTKeys helper#558
Copilot wants to merge 10 commits intomasterfrom
copilot/add-jwt-tests

Conversation

Copy link
Contributor

Copilot AI commented Jan 29, 2026

TypeScript compilation failed on cypress/support/jwt-helper.ts due to return type mismatch. The loadJWTKeys() function declared return type as JWTKeys but returned Cypress.Chainable<JWTKeys> from cy.fixture().

Changes

cypress/support/jwt-helper.ts

- export function loadJWTKeys(): JWTKeys {
+ export function loadJWTKeys(): Cypress.Chainable<JWTKeys> {
    return cy.fixture('jwt-keys').then((keys: JWTKeys) => keys)
  }

This aligns the return type with the other helper functions in the file, all of which correctly declare Cypress.Chainable<T> return types.


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Summary by CodeRabbit

  • Tests

    • Added comprehensive end-to-end tests for JWT authentication, covering valid tokens, invalid tokens, expired tokens, and session persistence across page navigations.
    • Added component tests to verify authentication state changes in the UI.
  • Chores

    • Added test fixtures and configuration for JWT authentication testing support.
  • Documentation

    • Added JWT authentication testing setup guide with configuration instructions and best practices.
    • Added implementation documentation for the test fixture infrastructure.

✏️ Tip: You can customize this high-level summary in your review settings.

Copilot AI and others added 3 commits January 29, 2026 14:46
Co-authored-by: jrhoads <1517672+jrhoads@users.noreply.github.com>
Co-authored-by: jrhoads <1517672+jrhoads@users.noreply.github.com>
Co-authored-by: jrhoads <1517672+jrhoads@users.noreply.github.com>
Copilot AI changed the title [WIP] Add tests for JWT usage in the project Add test coverage for JWT authentication Jan 29, 2026
Copilot AI requested a review from jrhoads January 29, 2026 14:54
Copilot AI and others added 3 commits January 29, 2026 15:09
Co-authored-by: jrhoads <1517672+jrhoads@users.noreply.github.com>
Co-authored-by: jrhoads <1517672+jrhoads@users.noreply.github.com>
Co-authored-by: jrhoads <1517672+jrhoads@users.noreply.github.com>
Copilot AI changed the title Add test coverage for JWT authentication Implement JWT test fixtures infrastructure and enable authentication tests Jan 29, 2026
@jrhoads jrhoads marked this pull request as ready for review January 29, 2026 16:10
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 29, 2026

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • 🔍 Trigger a full review

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In `@cypress.config.ts`:
- Around line 17-22: The current fixture-loading block (jwtKeysPath / jwtKeys /
config.env.jwtPublicKey) unconditionally sets Cypress env from a local file;
change it to only set config.env.jwtPublicKey when the app is actually
configured by checking process.env.NEXT_PUBLIC_JWT_PUBLIC_KEY (or set an
explicit flag like config.env.jwtPublicKeyConfigured) and use that to gate
setting config.env.jwtPublicKey; update the same logic in the other similar
block (lines referenced) so tests rely on NEXT_PUBLIC_JWT_PUBLIC_KEY presence
rather than a local fixture.

In `@cypress/fixtures/jwt-keys.json`:
- Around line 2-3: Remove the hard-coded "privateKey" value from the
jwt-keys.json fixture and stop committing private keys; keep only the
"publicKey" (or a placeholder). Update any tests or helpers that import
jwt-keys.json to obtain the private key at runtime instead—either by calling a
new helper like generateTestKeyPair() (which returns { publicKey, privateKey })
in a test setup hook (e.g., beforeAll/beforeEach) or by reading
process.env.TEST_JWT_PRIVATE_KEY injected by your CI/setup script; ensure
jwt-keys.json only contains the publicKey and that the generated/private key is
never written back to the repo. Also add/mention rotate credentials if this key
was already committed.

In `@cypress/support/jwt-helper.ts`:
- Around line 25-27: The function loadJWTKeys currently declares a return type
of JWTKeys but actually returns a Cypress chainable; change its signature to
return Cypress.Chainable<JWTKeys> (i.e., update the return type on loadJWTKeys)
so the TypeScript types reflect that it returns cy.fixture(...).then(...);
update any callers that assumed a synchronous JWTKeys value to use .then(...) or
await within a Cypress command if necessary (search for loadJWTKeys usages to
adjust).
- Around line 8-104: The jwt.sign/verify calls in generateTestJWT,
generateExpiredTestJWT and verifyTestJWT (used by setAuthenticatedSession and
loadJWTKeys) rely on Node's crypto and will break when bundled for the browser;
move JWT signing and verification into Cypress Node tasks instead (implement
cy.task handlers that use jsonwebtoken on the Node side and call those tasks
from generateTestJWT/generateExpiredTestJWT/verifyTestJWT) or, as an
alternative, configure browser polyfills or swap to a browser-compatible library
(e.g., jose) and update these functions to call the new implementation; ensure
setAuthenticatedSession continues to call the refactored generateTestJWT task
and that loadJWTKeys still returns the fixture via cy.fixture.
🧹 Nitpick comments (3)
docs/JWT_FIXTURES_IMPLEMENTATION.md (1)

19-40: Add language identifier to fenced code block.

The file structure code block is missing a language specifier, which triggers a linting warning. Consider adding text or plaintext for consistency.

📝 Suggested fix
-```
+```text
 cypress/
 ├── fixtures/
 │   ├── jwt-keys.json              # Test RSA key pair (NEW)
src/components/Header/NavRight.test.tsx (1)

83-109: Consider using Cypress's skip mechanism for clearer test reporting.

The current pattern with if (!condition) { cy.log(...); return; } silently passes the test rather than marking it as skipped in test reports. This can make it harder to identify which tests were actually executed vs. skipped.

💡 Alternative using it.skip or describe block

You could extract the conditional into a wrapper or use Cypress's built-in skip:

// Option 1: Conditional describe block
const jwtConfigured = Cypress.env('jwtPublicKey') || Cypress.env('NEXT_PUBLIC_JWT_PUBLIC_KEY')

describe('Valid JWT tests', { }, () => {
  before(function() {
    if (!jwtConfigured) {
      this.skip()
    }
  })
  
  it('should show signed in content when valid JWT token is present', () => {
    // test code without the skip logic
  })
})

This approach provides clearer test reporting showing tests as "skipped" rather than "passed".

cypress/e2e/jwtAuth.test.ts (1)

22-51: Optimize conditional test execution.

The beforeEach at lines 23-27 always executes setAuthenticatedSession, even when the tests will be immediately skipped due to missing JWT configuration. Consider moving the skip check to the beforeEach or restructuring to avoid unnecessary setup.

💡 Suggested optimization
 describe('Authenticated User (with valid JWT)', () => {
+  before(function() {
+    if (!Cypress.env('jwtPublicKey') && !Cypress.env('NEXT_PUBLIC_JWT_PUBLIC_KEY')) {
+      cy.log('Skipping: NEXT_PUBLIC_JWT_PUBLIC_KEY not configured for tests')
+      this.skip()
+    }
+  })
+
   beforeEach(() => {
-    // Set up authenticated session with valid JWT token using test fixtures
-    // This will work if NEXT_PUBLIC_JWT_PUBLIC_KEY is set to the test public key
     setAuthenticatedSession({ uid: 'test-user-123', name: 'Test User' })
   })

   it('should display user name when authenticated with valid JWT', () => {
-    // Skip if JWT public key is not configured for tests
-    if (!Cypress.env('jwtPublicKey') && !Cypress.env('NEXT_PUBLIC_JWT_PUBLIC_KEY')) {
-      cy.log('Skipping: NEXT_PUBLIC_JWT_PUBLIC_KEY not configured for tests')
-      return
-    }
-    
     cy.visit('/')
     cy.get('#sign-in', { timeout: 30000 }).should('be.visible')
   })

   it('should show user dropdown menu when authenticated with valid JWT', () => {
-    // Skip if JWT public key is not configured for tests
-    if (!Cypress.env('jwtPublicKey') && !Cypress.env('NEXT_PUBLIC_JWT_PUBLIC_KEY')) {
-      cy.log('Skipping: NEXT_PUBLIC_JWT_PUBLIC_KEY not configured for tests')
-      return
-    }
-    
     cy.visit('/')

Comment on lines 17 to 22
// Load JWT public key from fixture for tests
const jwtKeysPath = path.join(__dirname, 'cypress', 'fixtures', 'jwt-keys.json')
if (fs.existsSync(jwtKeysPath)) {
const jwtKeys = JSON.parse(fs.readFileSync(jwtKeysPath, 'utf8'))
config.env.jwtPublicKey = jwtKeys.publicKey
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, examine the cypress.config.ts file to see full context
fd cypress.config.ts -type f | head -5

Repository: datacite/akita

Length of output: 228


🏁 Script executed:

# Find and read the full cypress.config.ts file
cat -n cypress.config.ts 2>/dev/null || echo "File not found at root"

Repository: datacite/akita

Length of output: 1848


🏁 Script executed:

# Search for JWT-related skip patterns in test files
rg -n 'describe\.skip|it\.skip|xit\(|xdescribe\(|skip\(|jwtPublicKey|JWT_PUBLIC_KEY|NEXT_PUBLIC_JWT_PUBLIC_KEY' --type ts --type js | head -50

Repository: datacite/akita

Length of output: 1724


🏁 Script executed:

# Look for how Cypress.env is used with JWT configuration in tests
rg -B3 -A3 "Cypress\.env\('jwtPublicKey'\)|skipIf|skip.*jwt|jwt.*skip" --type ts --type js | head -60

Repository: datacite/akita

Length of output: 1719


Gate JWT test enablement on NEXT_PUBLIC_JWT_PUBLIC_KEY instead of local fixture (prevents test mismatch with unconfigurated app).

The fixture (cypress/fixtures/jwt-keys.json) is unconditionally loaded if it exists, which always sets config.env.jwtPublicKey. Tests skip only when both Cypress.env('jwtPublicKey') AND Cypress.env('NEXT_PUBLIC_JWT_PUBLIC_KEY') are absent—so with the fixture present, the skip condition never triggers even when the app isn't configured with JWT. This causes tests to run with a test key while the app may be using a different or missing key, creating false positives.

Instead, check process.env.NEXT_PUBLIC_JWT_PUBLIC_KEY and set the Cypress env only when that variable is present, or expose an explicit jwtPublicKeyConfigured flag to indicate whether JWT is ready for testing.

Suggested adjustment (illustrative)
-      const jwtKeysPath = path.join(__dirname, 'cypress', 'fixtures', 'jwt-keys.json')
-      if (fs.existsSync(jwtKeysPath)) {
-        const jwtKeys = JSON.parse(fs.readFileSync(jwtKeysPath, 'utf8'))
-        config.env.jwtPublicKey = jwtKeys.publicKey
-      }
+      const envPublicKey = process.env.NEXT_PUBLIC_JWT_PUBLIC_KEY
+      if (envPublicKey) {
+        config.env.jwtPublicKey = envPublicKey
+        config.env.jwtPublicKeyConfigured = true
+      } else {
+        config.env.jwtPublicKeyConfigured = false
+      }

Also applies to: 31-36

🤖 Prompt for AI Agents
In `@cypress.config.ts` around lines 17 - 22, The current fixture-loading block
(jwtKeysPath / jwtKeys / config.env.jwtPublicKey) unconditionally sets Cypress
env from a local file; change it to only set config.env.jwtPublicKey when the
app is actually configured by checking process.env.NEXT_PUBLIC_JWT_PUBLIC_KEY
(or set an explicit flag like config.env.jwtPublicKeyConfigured) and use that to
gate setting config.env.jwtPublicKey; update the same logic in the other similar
block (lines referenced) so tests rely on NEXT_PUBLIC_JWT_PUBLIC_KEY presence
rather than a local fixture.

Comment on lines 2 to 3
"publicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAj760PNWDk5AWonv/G63Q\n08b1XAqUdCVttXLxr6AEXcJeYWXwDPRZAGKBpMTVcu0SIl7I958ebVx2A1I4dNAZ\n6xCku2bgOzoOiFJqNF1EzaxhHbk2gBQt6q92X5RaPFZh3UUkmvISACoiDH+Mja2W\nkW3o8o4iRWaRUvo0sRpbv+O7PSx+3FBABGZSSz1wV7rz7YMjDUjHCF2gsS3XKeA3\nZzmwYlLmpxM1kD6h/XloO9OHgH2h2IlOyhm7VkhRYYc1auj5zJYKzKkWfCvbozF+\nrufZNFqMGjlUzmH5KYr4CcnuzYFTN0RxUJrCs1UDh/KbI2wZx3ZXXt4zp4QQNAO0\nRQIDAQAB\n-----END PUBLIC KEY-----",
"privateKey": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCPvrQ81YOTkBai\ne/8brdDTxvVcCpR0JW21cvGvoARdwl5hZfAM9FkAYoGkxNVy7RIiXsj3nx5tXHYD\nUjh00BnrEKS7ZuA7Og6IUmo0XUTNrGEduTaAFC3qr3ZflFo8VmHdRSSa8hIAKiIM\nf4yNrZaRbejyjiJFZpFS+jSxGlu/47s9LH7cUEAEZlJLPXBXuvPtgyMNSMcIXaCx\nLdcp4DdnObBiUuanEzWQPqH9eWg704eAfaHYiU7KGbtWSFFhhzVq6PnMlgrMqRZ8\nK9ujMX6u59k0WowaOVTOYfkpivgJye7NgVM3RHFQmsKzVQOH8psjbBnHdlde3jOn\nhBA0A7RFAgMBAAECggEAOcByVKCqCO7SkTyFPb8jT/q3GGAtzc492jFQtfFx36OY\nXMRiYioH2hY5pRPp+A8UgpeXYZld1a1YwrPVd+UmDKG2tY47F8CXFyEZh2lTm9ie\neh0wLtwsqIYPZo5JhMVl80r0zoXkQomq/V9/fmqYPFyuw0jkrwJq764T3nXLF/hS\nL8r9ieDtvxHjeDA+0Cj51wYZijQdeKrs/LLvUjW+du8quZfbdIR2pXDJMVORkTl9\n4ujt+CnpapUlCwzRqlr5Ln6AT+50n4Bx0J01k3da7svXQnLW7pvlkrenJtRG7/xJ\nZGc+TFvQQ6Gb/GeadVfLQNMPkHwEXm1lGFRa3Q5nvwKBgQDJMVteXwT7VFvvvq8X\nQGzHIIF5Go9I2l/DW5QFU/FKUsAOR5RqlCq4+WQry5C/KpULtTatarco0kp00oAO\ncxt+J3ph55n1xxepKjJrk1csCwHw6sKZcI0sCgy2uimZuyNBHV/k+aNWYN4cVj0t\nEw18TBn/cntVZJJQRApnLAw2nwKBgQC25xaTq0g1l+houN1TC2W0H9QpYPyXaqvS\n9swAo4Gvv5ESoYM64qGs9v7gU0xmf7xP2peNGf0+KGXIzhLgC9mAsiGgZISRI/NP\njJTtyty3Lgdct5z2BvyJ7aMdPdg1pldyE73nVFXU+TK9Lq+61diRVTcUf3td0BBc\nksQq0sgemwKBgBUX5qNrRONwwb7N+B9w8rah0tE2lqUlt/qMZGV2moqXSGl22bme\n1SfVhcoNqpxQQ5YZpqTh1lgiTAoZc7GQIebFDtCq7npVKEblFKowpWgJs2dlxYc+\nxJ5EY3bY57mlZBnUkZQ5FAXfXAoOhJVwNO6+L8+XWhTm2Wwu5gRRGuqzAoGAAXCo\nWNlMZD+h8NEjzPeWAWkOvpSo6HhKigqvaIHhD4UumzryUZBfPYFkWFfPji8LSIWs\nE8xUlhyzUHVu6JyvRbghU6X29T2XONUehxDF1Btkq3I2pik/68YXNq+5+BIrNha5\ntAyR8G9V2u93Kr1sSxikqmCmlAKDXnc5XCz0rmkCgYBfiFh8BKVjjOgThDu3SRXx\nx5p8BZidnH0gv+7ugdIycQ+oLuDFK2aksrUnQRgTyoO7t7Op3eg9oXpaOJ48ngCk\nadVZ/LaSNQMjCZNloDMqzgyAs/WKrKRKPUF4BmehfSkIa02leiowv920RV5lz2cn\nAqNjUvBofbfSx4IW+bC3tw==\n-----END PRIVATE KEY-----"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Avoid committing a private key to the repo (even test-only).

Secret scanners are already flagging this, and private keys in VCS are a compliance/security risk regardless of intent. Prefer generating the key pair at test runtime (or via a setup script) and keep the private key out of version control; only the public key needs to be committed.

🧰 Tools
🪛 Gitleaks (8.30.0)

[high] 3-3: Identified a Private Key, which may compromise cryptographic security and sensitive data encryption.

(private-key)

🤖 Prompt for AI Agents
In `@cypress/fixtures/jwt-keys.json` around lines 2 - 3, Remove the hard-coded
"privateKey" value from the jwt-keys.json fixture and stop committing private
keys; keep only the "publicKey" (or a placeholder). Update any tests or helpers
that import jwt-keys.json to obtain the private key at runtime instead—either by
calling a new helper like generateTestKeyPair() (which returns { publicKey,
privateKey }) in a test setup hook (e.g., beforeAll/beforeEach) or by reading
process.env.TEST_JWT_PRIVATE_KEY injected by your CI/setup script; ensure
jwt-keys.json only contains the publicKey and that the generated/private key is
never written back to the repo. Also add/mention rotate credentials if this key
was already committed.

Comment on lines 8 to 104
import jwt from 'jsonwebtoken'

export interface JWTPayload {
uid: string
name: string
exp?: number
iat?: number
}

export interface JWTKeys {
publicKey: string
privateKey: string
}

/**
* Load JWT test keys from fixtures
*/
export function loadJWTKeys(): JWTKeys {
return cy.fixture('jwt-keys').then((keys: JWTKeys) => keys)
}

/**
* Generate a valid JWT token for testing
* @param payload - The JWT payload (uid and name are required)
* @param expiresIn - Expiration time (default: '1h')
* @returns Promise<string> - The signed JWT token
*/
export function generateTestJWT(
payload: JWTPayload,
expiresIn: string = '1h'
): Cypress.Chainable<string> {
return cy.fixture('jwt-keys').then((keys: JWTKeys) => {
const token = jwt.sign(
payload,
keys.privateKey,
{
algorithm: 'RS256',
expiresIn
}
)
return token
})
}

/**
* Generate an expired JWT token for testing
* @param payload - The JWT payload
* @returns Promise<string> - The expired JWT token
*/
export function generateExpiredTestJWT(
payload: JWTPayload
): Cypress.Chainable<string> {
return cy.fixture('jwt-keys').then((keys: JWTKeys) => {
const token = jwt.sign(
{ ...payload, exp: Math.floor(Date.now() / 1000) - 3600 },
keys.privateKey,
{ algorithm: 'RS256' }
)
return token
})
}

/**
* Set up authenticated session with a valid JWT token
* @param user - User information (uid and name)
* @param expiresIn - Token expiration time (default: '1h')
*/
export function setAuthenticatedSession(
user: { uid: string; name: string },
expiresIn: string = '1h'
): Cypress.Chainable<void> {
return generateTestJWT(user, expiresIn).then((token) => {
const cookieValue = JSON.stringify({
authenticated: {
access_token: token
}
})
cy.setCookie('_datacite', cookieValue)
})
}

/**
* Verify JWT token with public key (for testing verification logic)
* @param token - The JWT token to verify
* @returns Promise<any> - The decoded payload or null if verification fails
*/
export function verifyTestJWT(token: string): Cypress.Chainable<any> {
return cy.fixture('jwt-keys').then((keys: JWTKeys) => {
return new Promise((resolve) => {
jwt.verify(token, keys.publicKey, { algorithms: ['RS256'] }, (error, payload) => {
if (error) {
resolve(null)
} else {
resolve(payload)
}
})
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, find the Cypress configuration file
fd -e ts -e js "cypress.config" .

Repository: datacite/akita

Length of output: 77


🏁 Script executed:

# Check for webpack or bundler configuration
fd -e js -e ts "webpack.config|vite.config|rollup.config" .

Repository: datacite/akita

Length of output: 40


🏁 Script executed:

# Search for cy.task implementations and crypto-related configuration
rg -n "cy\.task|crypto|polyfill" cypress/ src/ --type ts --type js

Repository: datacite/akita

Length of output: 126


🏁 Script executed:

# Check what dependencies are installed
find . -name "package.json" -type f | head -5 | xargs cat

Repository: datacite/akita

Length of output: 7818


🏁 Script executed:

cat -n cypress.config.ts

Repository: datacite/akita

Length of output: 1848


🏁 Script executed:

# Search for cy.task implementations related to JWT
rg -n "cy\.task|task.*jwt|jwt.*task" --type ts --type js

Repository: datacite/akita

Length of output: 40


🏁 Script executed:

# Check if there are other Cypress support files that might configure crypto
fd -e ts -e js . cypress/support/ cypress/plugins/

Repository: datacite/akita

Length of output: 218


🏁 Script executed:

# Check if there are any tests using the jwt-helper functions
rg -n "generateTestJWT|generateExpiredTestJWT|setAuthenticatedSession|verifyTestJWT" --type ts --type js

Repository: datacite/akita

Length of output: 910


🏁 Script executed:

# Look at the e2e.ts file to see how jwt-helper is used
cat -n cypress/support/e2e.ts

Repository: datacite/akita

Length of output: 1224


🏁 Script executed:

# Check if there's webpack configuration for browserify polyfills
cat -n cypress.config.ts | grep -A 20 "webpack"

Repository: datacite/akita

Length of output: 196


🏁 Script executed:

# Check if there's any browserify configuration in cypress.config or package.json
rg -n "browserify|polyfill" cypress.config.ts package.json

Repository: datacite/akita

Length of output: 123


🏁 Script executed:

# Check the actual test files to see if they fail or if there's a workaround
head -100 cypress/e2e/jwtAuth.test.ts

Repository: datacite/akita

Length of output: 3523


🏁 Script executed:

# Search for any Node.js crypto mock or polyfill setup
rg -n "crypto|mock|stub" cypress/support/ --type ts

Repository: datacite/akita

Length of output: 40


🏁 Script executed:

# Let me check if jsonwebtoken actually works with browserify or if there are any issues reported
# First, check if there's a .browserifyrc or any browserify config
find . -name ".browserifyrc*" -o -name "browserify.config*"

Repository: datacite/akita

Length of output: 40


🏁 Script executed:

# Check the component test that uses generateTestJWT to see if it actually passes or is skipped
head -150 src/components/Header/NavRight.test.tsx

Repository: datacite/akita

Length of output: 3782


🏁 Script executed:

# Search for any error logs or skipped tests related to JWT
rg -n "skip|pending|xdescribe|xit|TODO.*jwt|FIXME.*jwt" cypress/ src/components/

Repository: datacite/akita

Length of output: 390


🏁 Script executed:

# Check if there's a JWT_TEST_SETUP.md to understand the intended design
cat -n cypress/fixtures/JWT_TEST_SETUP.md

Repository: datacite/akita

Length of output: 7679


🏁 Script executed:

# Verify that jsonwebtoken actually has browser compatibility or if there are known issues
# Check if there are any comments in jwt-helper about this
cat -n cypress/support/jwt-helper.ts | head -20

Repository: datacite/akita

Length of output: 570


🏁 Script executed:

# Check if jsonwebtoken has browser polyfills or browserify compatibility
# Look for any browserify field in jsonwebtoken's package or any polyfill references
rg -n "browser|polyfill" package.json | grep -A5 -B5 "jsonwebtoken"

Repository: datacite/akita

Length of output: 40


🏁 Script executed:

# Check if there's actual test execution in CI that would catch this issue
cat -n .github/workflows/*.yml | grep -A10 -B10 "cypress\|test" | head -100

Repository: datacite/akita

Length of output: 3352


🏁 Script executed:

# Try to find if there's any working implementation of cy.task for Node operations
rg -n "cy.task" --type ts --type js

Repository: datacite/akita

Length of output: 40


🏁 Script executed:

# Check if there's any evidence that tests are actually running or being skipped
# Look for test output or CI configuration
find . -name "*.md" -type f | xargs grep -l "test\|jwt" | head -10

Repository: datacite/akita

Length of output: 609


🏁 Script executed:

# Search for any web-based implementations or mocks of jwt signing
rg -n "jest.mock|sinon|stub.*jwt" cypress/ src/ --type ts --type js

Repository: datacite/akita

Length of output: 40


🌐 Web query:

jsonwebtoken browserify browser compatibility crypto polyfill

💡 Result:

jsonwebtoken (auth0/node-jsonwebtoken) is fundamentally a Node.js JWT implementation and (transitively) depends on Node core modules like crypto (and often stream, util, etc.), which is why bundling it for the browser with Browserify/Webpack commonly fails unless you add polyfills. [1], [2]

If you still want to bundle jsonwebtoken in the browser

You’ll need Node-core polyfills, most importantly:

  • cryptocrypto-browserify (a JS port of Node’s crypto subset) [3]
  • Often also streamstream-browserify (because jsonwebtoken uses jws/streams), plus buffer, process, util depending on your bundler/errors. [2]

Typical Webpack 5-style fix (conceptually):

  • add resolve.fallback.crypto = require.resolve("crypto-browserify") (and other fallbacks as required by your build errors) [2]
  • install the corresponding polyfill packages (e.g., crypto-browserify) [3]

Caveat: even if it bundles, this increases bundle size and complexity, and you’re relying on JS crypto polyfills rather than the browser’s native WebCrypto in many cases. [3]

Usually better: use a browser-native JWT/JOSE library

If you need sign/verify in the browser, prefer a library designed for browsers (WebCrypto-first), e.g. jose which explicitly supports browsers and other web runtimes. [4]

If you only need to decode (not validate signatures) in the browser, use a decode-only library like jwt-decode. [5]

Rule of thumb: don’t sign HS256/secret-based JWTs in the browser (the secret would be exposed). Do signing server-side; in the browser, typically only decode/display claims, or verify tokens using public keys when appropriate.

Sources: auth0/node-jsonwebtoken repo [1], Webpack “can’t resolve crypto” error pattern [2], crypto-browserify docs [3], panva/jose support statement [4], auth0/jwt-decode guidance [5].


Move JWT signing/verification to cy.task or add crypto polyfills for browser bundling.

jsonwebtoken is a Node.js library that depends on the crypto module. When bundled for the browser via @cypress/browserify-preprocessor, it will fail at runtime unless you add explicit polyfills (crypto-browserify, stream-browserify, etc.). Tests currently skip when NEXT_PUBLIC_JWT_PUBLIC_KEY is not configured, but they will fail once that variable is set in CI.

Either move jwt.sign() and jwt.verify() into a cy.task that runs in the Node.js process, or install and configure the required polyfills in the bundler (e.g., via a custom webpack override in cypress.config.ts). Alternatively, use a browser-compatible JOSE library like jose if client-side JWT operations are needed.

🤖 Prompt for AI Agents
In `@cypress/support/jwt-helper.ts` around lines 8 - 104, The jwt.sign/verify
calls in generateTestJWT, generateExpiredTestJWT and verifyTestJWT (used by
setAuthenticatedSession and loadJWTKeys) rely on Node's crypto and will break
when bundled for the browser; move JWT signing and verification into Cypress
Node tasks instead (implement cy.task handlers that use jsonwebtoken on the Node
side and call those tasks from
generateTestJWT/generateExpiredTestJWT/verifyTestJWT) or, as an alternative,
configure browser polyfills or swap to a browser-compatible library (e.g., jose)
and update these functions to call the new implementation; ensure
setAuthenticatedSession continues to call the refactored generateTestJWT task
and that loadJWTKeys still returns the fixture via cy.fixture.

Comment on lines 25 to 27
export function loadJWTKeys(): JWTKeys {
return cy.fixture('jwt-keys').then((keys: JWTKeys) => keys)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix loadJWTKeys return type (it returns a Cypress chainable).

The current signature says JWTKeys but returns cy.fixture(...).then(...), which is Cypress.Chainable<JWTKeys>. This is a TypeScript correctness issue and will mislead callers.

Suggested fix
-export function loadJWTKeys(): JWTKeys {
+export function loadJWTKeys(): Cypress.Chainable<JWTKeys> {
   return cy.fixture('jwt-keys').then((keys: JWTKeys) => keys)
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function loadJWTKeys(): JWTKeys {
return cy.fixture('jwt-keys').then((keys: JWTKeys) => keys)
}
export function loadJWTKeys(): Cypress.Chainable<JWTKeys> {
return cy.fixture('jwt-keys').then((keys: JWTKeys) => keys)
}
🤖 Prompt for AI Agents
In `@cypress/support/jwt-helper.ts` around lines 25 - 27, The function loadJWTKeys
currently declares a return type of JWTKeys but actually returns a Cypress
chainable; change its signature to return Cypress.Chainable<JWTKeys> (i.e.,
update the return type on loadJWTKeys) so the TypeScript types reflect that it
returns cy.fixture(...).then(...); update any callers that assumed a synchronous
JWTKeys value to use .then(...) or await within a Cypress command if necessary
(search for loadJWTKeys usages to adjust).

Co-authored-by: jrhoads <1517672+jrhoads@users.noreply.github.com>
Copilot AI changed the title Implement JWT test fixtures infrastructure and enable authentication tests Fix return type annotation in loadJWTKeys helper Jan 29, 2026
@jrhoads jrhoads marked this pull request as draft January 29, 2026 16:44
… for signing and verifying tokens. Update documentation to reflect changes in key management and usage. Ensure private keys are never committed and clarify the role of public keys in tests. Adjust tests to skip gracefully when JWT configuration is incomplete.
@cypress
Copy link

cypress bot commented Jan 30, 2026

akita    Run #1863

Run Properties:  status check failed Failed #1863  •  git commit 0e1509c25d ℹ️: Merge 81f3a397e62565a98c108f7e28e460cebd227026 into d8bced833d2d5d663903a3dba64d...
Project akita
Branch Review copilot/add-jwt-tests
Run status status check failed Failed #1863
Run duration 02m 32s
Commit git commit 0e1509c25d ℹ️: Merge 81f3a397e62565a98c108f7e28e460cebd227026 into d8bced833d2d5d663903a3dba64d...
Committer Copilot
View all properties for this run ↗︎

Test results
Tests that failed  Failures 3
Tests that were flaky  Flaky 0
Tests that did not run due to a developer annotating a test with .skip  Pending 3
Tests that did not run due to a failure in a mocha hook  Skipped 0
Tests that passed  Passing 55
View all changes introduced in this branch ↗︎

Tests for review

Failed  cypress/e2e/jwtAuth.test.ts • 3 failed tests • Tests

View Output

Test Artifacts
JWT Authentication > Unauthenticated User > should not show user menu when not authenticated Test Replay Screenshots
JWT Authentication > Authenticated User (with valid JWT) > should show user dropdown menu when authenticated with valid JWT Test Replay Screenshots
JWT Authentication > Invalid JWT Token > should handle malformed cookie gracefully Test Replay Screenshots

…ety. Ensure it returns an empty string for invalid JSON or parsing errors.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants