173 lines
5.2 KiB
TypeScript
173 lines
5.2 KiB
TypeScript
![]() |
describe('Authentication Flow', () => {
|
||
|
beforeEach(() => {
|
||
|
cy.visit('/');
|
||
|
cy.clearLocalStorage();
|
||
|
});
|
||
|
|
||
|
describe('Google OAuth Sign In', () => {
|
||
|
it('should display sign in modal when accessing protected features', () => {
|
||
|
// Try to upload without signing in
|
||
|
cy.get('[data-cy=drop-area]').should('be.visible');
|
||
|
cy.get('[data-cy=file-input]').selectFile('cypress/fixtures/test-image.jpg', { force: true });
|
||
|
|
||
|
// Should show auth modal
|
||
|
cy.get('[data-cy=auth-modal]').should('be.visible');
|
||
|
cy.get('[data-cy=google-signin-btn]').should('be.visible');
|
||
|
});
|
||
|
|
||
|
it('should redirect to Google OAuth when clicking sign in', () => {
|
||
|
cy.get('[data-cy=signin-btn]').click();
|
||
|
cy.get('[data-cy=auth-modal]').should('be.visible');
|
||
|
|
||
|
// Mock Google OAuth response
|
||
|
cy.intercept('GET', '/api/auth/google', {
|
||
|
statusCode: 302,
|
||
|
headers: {
|
||
|
Location: 'https://accounts.google.com/oauth/authorize?...',
|
||
|
},
|
||
|
}).as('googleAuth');
|
||
|
|
||
|
cy.get('[data-cy=google-signin-btn]').click();
|
||
|
cy.wait('@googleAuth');
|
||
|
});
|
||
|
|
||
|
it('should handle successful authentication', () => {
|
||
|
// Mock successful auth callback
|
||
|
cy.intercept('GET', '/api/auth/google/callback*', {
|
||
|
statusCode: 200,
|
||
|
body: {
|
||
|
token: 'mock-jwt-token',
|
||
|
user: {
|
||
|
id: 'user-123',
|
||
|
email: 'test@example.com',
|
||
|
plan: 'BASIC',
|
||
|
quotaRemaining: 50,
|
||
|
},
|
||
|
},
|
||
|
}).as('authCallback');
|
||
|
|
||
|
// Mock user profile endpoint
|
||
|
cy.intercept('GET', '/api/auth/me', {
|
||
|
statusCode: 200,
|
||
|
body: {
|
||
|
id: 'user-123',
|
||
|
email: 'test@example.com',
|
||
|
plan: 'BASIC',
|
||
|
quotaRemaining: 50,
|
||
|
quotaLimit: 50,
|
||
|
},
|
||
|
}).as('userProfile');
|
||
|
|
||
|
// Simulate successful auth by setting token
|
||
|
cy.window().then((win) => {
|
||
|
win.localStorage.setItem('seo_auth_token', 'mock-jwt-token');
|
||
|
});
|
||
|
|
||
|
cy.reload();
|
||
|
|
||
|
// Should show user menu instead of sign in button
|
||
|
cy.get('[data-cy=user-menu]').should('be.visible');
|
||
|
cy.get('[data-cy=signin-menu]').should('not.exist');
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('User Session', () => {
|
||
|
beforeEach(() => {
|
||
|
// Set up authenticated user
|
||
|
cy.window().then((win) => {
|
||
|
win.localStorage.setItem('seo_auth_token', 'mock-jwt-token');
|
||
|
});
|
||
|
|
||
|
cy.intercept('GET', '/api/auth/me', {
|
||
|
statusCode: 200,
|
||
|
body: {
|
||
|
id: 'user-123',
|
||
|
email: 'test@example.com',
|
||
|
plan: 'BASIC',
|
||
|
quotaRemaining: 30,
|
||
|
quotaLimit: 50,
|
||
|
},
|
||
|
}).as('userProfile');
|
||
|
});
|
||
|
|
||
|
it('should display user quota information', () => {
|
||
|
cy.visit('/');
|
||
|
cy.wait('@userProfile');
|
||
|
|
||
|
cy.get('[data-cy=quota-used]').should('contain', '20'); // 50 - 30
|
||
|
cy.get('[data-cy=quota-limit]').should('contain', '50');
|
||
|
cy.get('[data-cy=quota-fill]').should('have.css', 'width', '40%'); // 20/50 * 100
|
||
|
});
|
||
|
|
||
|
it('should handle logout', () => {
|
||
|
cy.intercept('POST', '/api/auth/logout', {
|
||
|
statusCode: 200,
|
||
|
body: { message: 'Logged out successfully' },
|
||
|
}).as('logout');
|
||
|
|
||
|
cy.visit('/');
|
||
|
cy.wait('@userProfile');
|
||
|
|
||
|
cy.get('[data-cy=user-menu]').click();
|
||
|
cy.get('[data-cy=logout-link]').click();
|
||
|
|
||
|
cy.wait('@logout');
|
||
|
|
||
|
// Should clear local storage and show sign in button
|
||
|
cy.window().its('localStorage').invoke('getItem', 'seo_auth_token').should('be.null');
|
||
|
cy.get('[data-cy=signin-menu]').should('be.visible');
|
||
|
});
|
||
|
|
||
|
it('should handle expired token', () => {
|
||
|
cy.intercept('GET', '/api/auth/me', {
|
||
|
statusCode: 401,
|
||
|
body: { message: 'Token expired' },
|
||
|
}).as('expiredToken');
|
||
|
|
||
|
cy.visit('/');
|
||
|
cy.wait('@expiredToken');
|
||
|
|
||
|
// Should clear token and show sign in
|
||
|
cy.window().its('localStorage').invoke('getItem', 'seo_auth_token').should('be.null');
|
||
|
cy.get('[data-cy=signin-menu]').should('be.visible');
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('Quota Enforcement', () => {
|
||
|
it('should show upgrade modal when quota exceeded', () => {
|
||
|
cy.window().then((win) => {
|
||
|
win.localStorage.setItem('seo_auth_token', 'mock-jwt-token');
|
||
|
});
|
||
|
|
||
|
cy.intercept('GET', '/api/auth/me', {
|
||
|
statusCode: 200,
|
||
|
body: {
|
||
|
id: 'user-123',
|
||
|
email: 'test@example.com',
|
||
|
plan: 'BASIC',
|
||
|
quotaRemaining: 0,
|
||
|
quotaLimit: 50,
|
||
|
},
|
||
|
}).as('userProfileNoQuota');
|
||
|
|
||
|
cy.intercept('POST', '/api/batches', {
|
||
|
statusCode: 400,
|
||
|
body: { message: 'Quota exceeded' },
|
||
|
}).as('quotaExceeded');
|
||
|
|
||
|
cy.visit('/');
|
||
|
cy.wait('@userProfileNoQuota');
|
||
|
|
||
|
// Try to upload when quota is 0
|
||
|
cy.get('[data-cy=file-input]').selectFile('cypress/fixtures/test-image.jpg', { force: true });
|
||
|
cy.get('[data-cy=keyword-input]').type('test keywords');
|
||
|
cy.get('[data-cy=enhance-btn]').click();
|
||
|
|
||
|
cy.wait('@quotaExceeded');
|
||
|
|
||
|
// Should show upgrade modal
|
||
|
cy.get('[data-cy=subscription-modal]').should('be.visible');
|
||
|
cy.get('[data-cy=upgrade-btn]').should('have.length.greaterThan', 0);
|
||
|
});
|
||
|
});
|
||
|
});
|