Skip to content

Commit

Permalink
src/components: add component TableNotifications for displaying user …
Browse files Browse the repository at this point in the history
…notifications (#551)

* core component html

* labels

* update tests

* add mark as read functionality + button mark all as read

* add icon and link

* fix column type

* fix column type

* update font weight + tests

* table notification row click + enums

* expose enum

---------

Co-authored-by: Šimon Macek <[email protected]>
  • Loading branch information
maceksimon and Šimon Macek authored Sep 20, 2024
1 parent 46cb483 commit 2cb2202
Show file tree
Hide file tree
Showing 9 changed files with 531 additions and 7 deletions.
163 changes: 163 additions & 0 deletions src/components/__tests__/TableNotifications.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import { colors, date } from 'quasar';
import TableNotifications from 'components/profile/TableNotifications.vue';
import { i18n } from '../../boot/i18n';

// colors
const { getPaletteColor } = colors;
const grey10 = getPaletteColor('grey-10');

// selectors
const classSelectorQBtn = '.q-btn';
const dataSelectorNotificationTitle = '[data-cy="notification-title"]';
const dataSelectorNotificationTimestamp = '[data-cy="notification-timestamp"]';
const dataSelectorNotificationState = '[data-cy="notification-state"]';
const dataSelectorNotificationAction = '[data-cy="notification-action"]';
const dataSelectorNotificationIcon = '[data-cy="notification-icon"]';
const dataSelectorNotificationVerbal = '[data-cy="notification-verbal"]';
const selectorTableNotifications = 'table-notifications';
const selectorNotificationRow = 'notification-row';
const selectorButtonMarkAllAsRead = 'button-mark-all-as-read';

// variables
const defaultTablePostsPerPage = 5;
const fontWeightBold = '700';
const fontWeightRegular = '400';

describe('<TableNotifications>', () => {
it('has translation for all strings', () => {
cy.testLanguageStringsInContext(
[
'labelAction',
'labelDate',
'labelRead',
'labelState',
'labelTitle',
'labelUnread',
],
'notifications',
i18n,
);
});

let notifications;

before(() => {
cy.fixture('tableNotifications').then((data) => {
notifications = data;
});
});

context('desktop', () => {
beforeEach(() => {
cy.mount(TableNotifications, {
props: {},
});
cy.viewport('macbook-16');
});

coreTests();
});

function coreTests() {
it('renders component', () => {
cy.dataCy(selectorTableNotifications).should('be.visible');
});

it('renders notifications', () => {
cy.dataCy(selectorNotificationRow)
.should('be.visible')
.should('have.length', defaultTablePostsPerPage);
cy.dataCy(selectorNotificationRow).each((row, index) => {
const notification = notifications[index];
cy.wrap(row)
.find(dataSelectorNotificationTitle)
.should('be.visible')
.should('contain', notification.verb);
cy.wrap(row).find(dataSelectorNotificationIcon).should('be.visible');
cy.wrap(row).find(dataSelectorNotificationVerbal).should('be.visible');
if (notification.data.url) {
cy.wrap(row)
.find(dataSelectorNotificationVerbal)
.and('have.prop', 'tagName', 'A')
.and('have.attr', 'href', notification.data.url)
.and('have.attr', 'target', '_blank');
} else {
cy.wrap(row)
.find(dataSelectorNotificationVerbal)
.should('have.prop', 'tagName', 'SPAN')
.and('have.color', grey10);
}
if (notification.unread) {
cy.wrap(row)
.find(dataSelectorNotificationVerbal)
.should('have.css', 'font-weight', fontWeightBold);
} else {
cy.wrap(row)
.find(dataSelectorNotificationVerbal)
.should('have.css', 'font-weight', fontWeightRegular);
}
cy.wrap(row)
.find(dataSelectorNotificationTimestamp)
.should('be.visible')
.and(
'contain',
date.formatDate(
new Date(String(notification.timestamp)),
'D. MMM. YYYY',
),
);
cy.wrap(row)
.find(dataSelectorNotificationState)
.should('be.visible')
.and(
'contain',
notification.unread
? i18n.global.t('notifications.labelUnread')
: i18n.global.t('notifications.labelRead'),
);
cy.wrap(row).find(dataSelectorNotificationAction).should('be.visible');
});
});

it('allows to mark notification as read', () => {
cy.dataCy(selectorNotificationRow)
.first()
.find(dataSelectorNotificationState)
.should('contain', i18n.global.t('notifications.labelUnread'));
cy.dataCy(selectorNotificationRow)
.first()
.find(dataSelectorNotificationAction)
.find(classSelectorQBtn)
.click();
cy.dataCy(selectorNotificationRow)
.first()
.find(dataSelectorNotificationState)
.should('not.contain', i18n.global.t('notifications.labelUnread'))
.and('contain', i18n.global.t('notifications.labelRead'));
});

it('marks notification as read when row is clicked', () => {
cy.dataCy(selectorNotificationRow).last().click();
cy.dataCy(selectorNotificationRow)
.last()
.find(dataSelectorNotificationState)
.should('not.contain', i18n.global.t('notifications.labelUnread'))
.and('contain', i18n.global.t('notifications.labelRead'));
});

it('allows to mark all notifications as read', () => {
cy.dataCy(selectorButtonMarkAllAsRead)
.should('be.visible')
.and('not.be.disabled')
.click();
cy.dataCy(selectorNotificationRow).each((row) => {
cy.wrap(row)
.find(dataSelectorNotificationState)
.should('contain', i18n.global.t('notifications.labelRead'));
});
cy.dataCy(selectorButtonMarkAllAsRead)
.should('be.visible')
.and('be.disabled');
});
}
});
5 changes: 4 additions & 1 deletion src/components/profile/ProfileTabs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*
* @components
* - `ProfileDetails`: Component to display a ProfileDetails section.
* - `TableNotifications`: Component to display a table of notifications.
*
* @example
* <profile-tabs />
Expand All @@ -19,6 +20,7 @@ import { defineComponent, ref } from 'vue';
// components
import ProfileDetails from './ProfileDetails.vue';
import TableNotifications from './TableNotifications.vue';
// routes
import { routesConf } from '../../router/routes_conf';
Expand All @@ -35,6 +37,7 @@ export default defineComponent({
name: 'ProfileTabs',
components: {
ProfileDetails,
TableNotifications,
},
setup() {
const activeTab = ref(tabsProfile.none);
Expand Down Expand Up @@ -113,7 +116,7 @@ export default defineComponent({
:name="tabsProfile.notifications"
data-cy="profile-tabs-panel-notifications"
>
<!-- <profile-notifications /> -->
<table-notifications />
</q-tab-panel>
</q-tab-panels>
</div>
Expand Down
Loading

0 comments on commit 2cb2202

Please sign in to comment.