add more tests for payment history page, responsive mobile view

This commit is contained in:
Nuwan 2024-04-24 20:44:00 +05:30
parent c2ffbff216
commit 81c1c17a2f
20 changed files with 287 additions and 85 deletions

View File

@ -8,39 +8,82 @@ describe('Payments Page', () => {
cy.intercept('GET', /\S+\/invoice_history\?limit=10&cursor=0/, { fixture: 'payments_page1' }).as('getPayments1');
cy.intercept('GET', /\S+\/invoice_history\?limit=10&cursor=10/, { fixture: 'payments_page2' }).as('getPayments2');
cy.intercept('GET', /\S+\/invoice_history\?limit=10&cursor=20/, { fixture: 'payments_page3' }).as('getPayments3');
})
it('should list user\'s payments', () => {
// Call the external API that fetches the payment records
cy.visit('/account/payments')
cy.wait('@getPayments1')
cy.get('[data-testid="paymentsListTable"]').should('be.visible').find('tbody tr').first().within(() => {
cy.contains('05/01/2022')
})
})
it.only('paginate through the payments', () => {
// Call the external API that fetches the payment records
cy.visit('/account/payments')
cy.wait('@getPayments1')
cy.get('[data-testid="paymentsListTable"]').should('be.visible').find('tbody tr').first().within(() => {
cy.contains('12/01/2022')
})
// Click the next page button
cy.get('[data-testid="nextPageButton"]').click()
cy.wait('@getPayments2')
cy.get('[data-testid="paymentsListTable"]').should('be.visible').find('tbody tr').first().within(() => {
cy.contains('02/01/2022')
})
// Click the next page button
cy.get('[data-testid="nextPageButton"]').click()
cy.wait('@getPayments3')
cy.get('[data-testid="paymentsListTable"]').should('be.visible').find('tbody tr').first().within(() => {
cy.contains('03/01/2021')
})
});
describe('in desktop', () => {
beforeEach(() => {
cy.viewport('macbook-13');
});
it('should list user\'s payments', () => {
// Call the external API that fetches the payment records
cy.visit('/account/payments')
cy.wait('@getPayments1')
cy.get('[data-testid="paymentsListTable"]').should('be.visible').find('tbody tr td').first().within(() => {
cy.contains('12/01/2022')
})
})
it('paginate through the payments', () => {
// Call the external API that fetches the payment records
cy.visit('/account/payments')
cy.wait('@getPayments1')
cy.get('[data-testid="paymentsListTable"]').should('be.visible').find('tbody tr').first().within(() => {
cy.contains('12/01/2022')
})
// Click the next page button
cy.get('[data-testid="nextPageButton"]').click()
cy.wait('@getPayments2')
cy.get('[data-testid="paymentsListTable"]').should('be.visible').find('tbody tr:nth-child(11)').first().within(() => {
cy.contains('02/01/2022')
})
// Click the next page button
cy.get('[data-testid="nextPageButton"]').click()
cy.wait('@getPayments3')
cy.get('[data-testid="paymentsListTable"]').should('be.visible').find('tbody tr:nth-child(22)').first().within(() => {
cy.contains('03/01/2021')
})
});
});
describe('in mobile', () => {
beforeEach(() => {
cy.viewport('iphone-6');
});
it('should list user\'s payments', () => {
// Call the external API that fetches the payment records
cy.visit('/account/payments')
cy.wait('@getPayments1')
cy.get('[data-testid=paymentSwiper]').should('be.visible')
for (let i = 0; i < 9; i++) {
cy.get('.swiper-button-next').click();
cy.wait(500);
}
cy.wait('@getPayments2')
for (let i = 0; i < 10; i++) {
cy.get('.swiper-button-next').click();
cy.wait(500);
}
cy.get('.swiper-button-next').click();
cy.wait('@getPayments3')
for (let i = 0; i < 2; i++) {
cy.get('.swiper-button-next').click();
cy.wait(500);
}
cy.get('.swiper-button-next').should('have.class', 'swiper-button-disabled');
});
})
})

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -9,4 +9,9 @@
.borderless td, .borderless th {
border: none;
}
.swiper-card {
box-shadow: none !important;
border: solid 1px #eee;
}

View File

@ -104,10 +104,10 @@
object-fit: cover;
}
.swiper-person-card{
box-shadow: none !important;
border: solid 1px #eee;
}
// .swiper-person-card{
// box-shadow: none !important;
// border: solid 1px #eee;
// }
.latency-badge{
min-width: 0%;

View File

@ -1,9 +1,12 @@
import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Card, CardBody, Row, Col, Table, Alert, Button } from 'reactstrap';
import { Card, CardBody, Row, Col, Alert } from 'reactstrap';
import FalconCardHeader from '../common/FalconCardHeader';
import { getInvoiceHistory } from '../../helpers/rest';
import { isIterableArray } from '../../helpers/utils';
import { useResponsive } from '@farfetch/react-context-responsive';
import PaymentHistoryList from '../payments/JKPaymentHistoryList';
import PaymentHistorySwiper from '../payments/JKPaymentHistorySwiper';
const JKPaymentHistory = () => {
const { t } = useTranslation('account');
@ -11,6 +14,7 @@ const JKPaymentHistory = () => {
const LIMIT = 10;
const [offset, setOffset] = useState(0);
const [loading, setLoading] = useState(false);
const { greaterThan } = useResponsive();
const fetchPayments = async () => {
const options = { limit: LIMIT, cursor: offset };
@ -18,11 +22,11 @@ const JKPaymentHistory = () => {
setLoading(true);
const response = await getInvoiceHistory(options);
const data = await response.json();
setPayments(data.entries);
setPayments(prev => [...prev, ...data.entries]);
setOffset(prev => prev + LIMIT);
}catch(error) {
} catch (error) {
console.error(error);
}finally {
} finally {
setLoading(false);
}
};
@ -30,13 +34,13 @@ const JKPaymentHistory = () => {
useEffect(async () => {
// fetch payments
const options = { cursor: offset, limit: LIMIT };
await fetchPayments(options);
await fetchPayments(options);
}, []);
const goToNextPage = async () => {
const options = { cursor: offset, limit: LIMIT };
await fetchPayments(options);
}
};
return (
<Card>
@ -46,36 +50,11 @@ const JKPaymentHistory = () => {
<Col className="mb-2 col-md-9 col-lg-8 m-auto">
{isIterableArray(payments) && payments.length ? (
<>
<Table striped bordered className="fs--1" data-testid="paymentsListTable">
<thead className="bg-200 text-900">
<tr>
<th scope="col">{t('payments.payment_attributes.date')}</th>
<th scope="col" style={{ minWidth: 250 }}>
{t('payments.payment_attributes.description')}
</th>
<th scope="col">{t('payments.payment_attributes.status')}</th>
<th scope="col">{t('payments.payment_attributes.amount')}</th>
</tr>
</thead>
<tbody className="list">
{payments.map(payment => (
<tr key={payment.id}>
<td>{new Date(payment.created_at).toLocaleDateString("en-US", {
year: "numeric",
month: "2-digit",
day: "2-digit"}
)}
</td>
<td>{payment.description}</td>
<td>{payment.status}</td>
<td>{`$${(payment.total_in_cents / 100).toFixed(2)}`}</td>
</tr>
))}
</tbody>
</Table>
<Button onClick={goToNextPage} data-testid="nextPageButton" disabled={loading}>
{loading ? <span>{t('payments.loading')}</span> : <span>{t('payments.load_more')}</span> }
</Button>
{greaterThan.sm ? (
<PaymentHistoryList payments={payments} goToNextPage={goToNextPage} loading={loading} />
) : (
<PaymentHistorySwiper payments={payments} goToNextPage={goToNextPage} />
)}
</>
) : (
<Alert color="info" className="mb-0">

View File

@ -44,7 +44,7 @@ const JKPeopleSwiper = ({ people, goNextPage }) => {
>
{people.map((person, index) => (
<SwiperSlide key={`people-swiper-item-${person.id}`}>
<Card className="swiper-person-card">
<Card className="swiper-card">
<CardHeader className="bg-200">
<div className="avatar avatar-xl d-inline-block me-2 mr-2">
<JKProfileAvatar url={person.photo_url} size="xl"/>

View File

@ -0,0 +1,66 @@
import React from 'react';
import { useResponsive } from '@farfetch/react-context-responsive';
import { Row, Col } from 'reactstrap';
import { useTranslation } from 'react-i18next';
const JKPayment = ({ payment }) => {
const { greaterThan } = useResponsive();
const { t } = useTranslation('account');
return (
<>
{greaterThan.sm ? (
<tr key={payment.id}>
<td>
{new Date(payment.created_at).toLocaleDateString('en-US', {
year: 'numeric',
month: '2-digit',
day: '2-digit'
})}
</td>
<td>{payment.description}</td>
<td className='text-capitalize'>{payment.status}</td>
<td>{`$${(payment.total_in_cents / 100).toFixed(2)}`}</td>
</tr>
) : (
<>
<small>
<Row>
<Col xs={4} className="mb-2 text-right">
{t('payments.payment_attributes.date')}:
</Col>
<Col xs={8} className="mb-2 pl-2">
{new Date(payment.created_at).toLocaleDateString('en-US', {
year: 'numeric',
month: '2-digit',
day: '2-digit'
})}
</Col>
</Row>
<Row>
<Col xs={4} className="mb-2 text-right">
{t('payments.payment_attributes.description')}:
</Col>
<Col xs={8} className="mb-2 pl-2">
{payment.description}
</Col>
</Row>
<Row>
<Col xs={4} className="mb-2 text-right">{t('payments.payment_attributes.status')}:</Col>
<Col xs={6} className="mb-2 pl-2 text-capitalize">
{payment.status}
</Col>
</Row>
<Row>
<Col xs={4} className="mb-2 text-right">{t('payments.payment_attributes.amount')}:</Col>
<Col xs={8} className="mb-2 pl-2">
{`$${(payment.total_in_cents / 100).toFixed(2)}`}
</Col>
</Row>
</small>
</>
)}
</>
);
};
export default JKPayment;

View File

@ -0,0 +1,35 @@
import React from 'react'
import { Table, Button } from 'reactstrap';
import { useTranslation } from 'react-i18next';
import JKPayment from './JKPayment';
const JKPaymentHistoryList = ({payments, goToNextPage, loading}) => {
const { t } = useTranslation('account');
return (
<>
<Table striped bordered className="fs--1" data-testid="paymentsListTable">
<thead className="bg-200 text-900">
<tr>
<th scope="col">{t('payments.payment_attributes.date')}</th>
<th scope="col" style={{ minWidth: 250 }}>
{t('payments.payment_attributes.description')}
</th>
<th scope="col">{t('payments.payment_attributes.status')}</th>
<th scope="col">{t('payments.payment_attributes.amount')}</th>
</tr>
</thead>
<tbody className="list">
{payments.map(payment => (
<JKPayment payment={payment} />
))}
</tbody>
</Table>
<Button onClick={goToNextPage} data-testid="nextPageButton" disabled={loading}>
{loading ? <span>{t('payments.loading')}</span> : <span>{t('payments.load_more')}</span> }
</Button>
</>
)
}
export default JKPaymentHistoryList

View File

@ -0,0 +1,73 @@
import React from 'react';
import PropTypes from 'prop-types';
import { useTranslation } from 'react-i18next';
// import Swiper core and required modules
import SwiperCore, { Navigation, Pagination, Scrollbar, A11y } from 'swiper';
// Import Swiper React components
import { Swiper, SwiperSlide } from 'swiper/react';
// Import Swiper styles
import 'swiper/swiper.scss';
import 'swiper/components/navigation/navigation.scss';
import 'swiper/components/pagination/pagination.scss';
import 'swiper/components/scrollbar/scrollbar.scss';
import { Card, CardBody, CardHeader } from 'reactstrap';
import JKPayment from './JKPayment';
SwiperCore.use([Navigation, Pagination, Scrollbar, A11y]);
const JKPaymentHistorySwiper = ({ payments, goToNextPage }) => {
const { t } = useTranslation('account');
return (
<>
<Swiper
spaceBetween={0}
slidesPerView={1}
onSlideChange={(e) => console.log('slide change', e)}
onSlideNextTransitionEnd={swiper => {
if(swiper.isEnd){
goToNextPage()
}
}}
pagination={{
clickable: true,
type: 'custom'
}}
navigation={{
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev'
}}
data-testid="paymentSwiper"
>
{payments.map((payment, index) => (
<SwiperSlide key={`people-swiper-item-${payment.id}`}>
<Card className="swiper-card">
<CardHeader className="bg-200 text-center">
<h5 className="d-inline-block align-top mt-1">{t('payments.payment')}</h5>
</CardHeader>
<CardBody>
<JKPayment payment={payment} />
</CardBody>
</Card>
</SwiperSlide>
))}
</Swiper>
<div className="py-4 px-6 bg-white border-top w-100 fixed-bottom">
<div className="swiper-pagination" />
<div className="swiper-button-prev" />
<div className="swiper-button-next" />
</div>
</>
);
};
JKPaymentHistorySwiper.propTypes = {
payments: PropTypes.arrayOf(PropTypes.instanceOf(Object)),
goToNextPage: PropTypes.func
};
export default JKPaymentHistorySwiper;

View File

@ -44,7 +44,7 @@ const JKFriendsSwiper = ({ friends, goNextPage }) => {
>
{friends.map((friend, index) => (
<SwiperSlide key={`friends-swiper-item-${friend.id}`}>
<Card className="swiper-person-card">
<Card className="swiper-card">
<CardHeader className="bg-200">
<div className="avatar avatar-xl d-inline-block me-2 mr-2">
<JKProfileAvatar url={friend.photo_url} size="xl"/>

View File

@ -53,7 +53,7 @@ const JKLobbyUserSwiper = ({ onlineMusicians, setSelectedUsers, loadingStatus })
>
{onlineMusicians.map((musician, index) => (
<SwiperSlide key={`session-lobby-swiper-item-${musician.id}`}>
<Card className="swiper-person-card">
<Card className="swiper-card">
<CardHeader className="bg-200">
<div className="avatar avatar-xl d-inline-block me-2 mr-2">
<JKProfileAvatar url={musician.photo_url} size="xl" />

View File

@ -43,7 +43,7 @@ const JKSessionSwiper = ({ sessions }) => {
>
{sessions.map((session, index) => (
<SwiperSlide key={`sessions-swiper-item-${session.id}`}>
<Card className="swiper-person-card">
<Card className="swiper-card">
<CardHeader className="text-center bg-200">
<h4 className="d-inline-block align-center mt-1">Session</h4>
</CardHeader>

View File

@ -87,6 +87,7 @@
},
"payments": {
"page_title": "Payment History",
"payment": "Payment",
"payment_attributes": {
"date": "Date",
"description": "Description",