Skip to content

Commit da9b204

Browse files
authored
Add markdown in tcr description (#725)
* Add markdown function for requestor details Signed-off-by: Tushar Goel <[email protected]> * Added event listener Signed-off-by: Tushar Goel <[email protected]> * Add condition for checking if markdown is enabled Signed-off-by: Tushar Goel <[email protected]> * Add tests Signed-off-by: Tushar Goel <[email protected]> * Use toContain to check markdown instead of toBe Signed-off-by: Tushar Goel <[email protected]> * Fix markdown parsing Signed-off-by: Tushar Goel <[email protected]> * Add className for description Value Signed-off-by: Tushar Goel <[email protected]> * Address review comments Signed-off-by: Tushar Goel <[email protected]> * Fix tests Signed-off-by: Tushar Goel <[email protected]> * Fix tests Signed-off-by: Tushar Goel <[email protected]> * Fix tests Signed-off-by: Tushar Goel <[email protected]> --------- Signed-off-by: Tushar Goel <[email protected]>
1 parent b409f74 commit da9b204

File tree

5 files changed

+174
-2
lines changed

5 files changed

+174
-2
lines changed

__tests__/task-requests/task-requestDetails.test.js

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,97 @@ describe('Task request details page', () => {
9797
});
9898
});
9999

100+
describe('Task request details page with markdown support in description', () => {
101+
let browser;
102+
let page;
103+
jest.setTimeout(60000);
104+
105+
beforeAll(async () => {
106+
browser = await puppeteer.launch({
107+
headless: 'new',
108+
ignoreHTTPSErrors: true,
109+
args: ['--incognito', '--disable-web-security'],
110+
devtools: false,
111+
});
112+
page = await browser.newPage();
113+
await page.setRequestInterception(true);
114+
page.on('request', (interceptedRequest) => {
115+
const url = interceptedRequest.url();
116+
if (urlMappings.hasOwnProperty(url)) {
117+
interceptedRequest.respond({
118+
...defaultMockResponseHeaders,
119+
body: JSON.stringify(urlMappings[url]),
120+
});
121+
} else {
122+
interceptedRequest.continue();
123+
}
124+
});
125+
await page.goto(
126+
'http://localhost:8000/task-requests/details/?id=dM5wwD9QsiTzi7eG7Oq6',
127+
);
128+
});
129+
130+
afterAll(async () => {
131+
await browser.close();
132+
});
133+
134+
it('Checks the Modal working as expected', async () => {
135+
await page.waitForNetworkIdle();
136+
await page.click('.info__more');
137+
await page.waitForSelector('#requestor_details_modal_content', {
138+
visible: true,
139+
});
140+
const modalHeading = await page.$eval(
141+
'[data-modal-header="requestor-details-header"]',
142+
(element) => element.textContent,
143+
);
144+
expect(modalHeading).toBe('Requestor Details');
145+
146+
const proposedStartDateHeading = await page.$eval(
147+
'[data-modal-start-date-text="proposed-start-date-text"]',
148+
(element) => element.textContent,
149+
);
150+
expect(proposedStartDateHeading).toBe('Proposed Start Date:');
151+
152+
const proposedStartDateValue = await page.$eval(
153+
'[data-modal-start-date-value="proposed-start-date-value"]',
154+
(element) => element.textContent,
155+
);
156+
expect(proposedStartDateValue).toBe('30-10-2023');
157+
158+
const proposedEndDateHeading = await page.$eval(
159+
'[data-modal-end-date-text="proposed-end-date-text"]',
160+
(element) => element.textContent,
161+
);
162+
expect(proposedEndDateHeading).toBe('Proposed Deadline:');
163+
164+
const proposedEndDateValue = await page.$eval(
165+
'[data-modal-end-date-value="proposed-end-date-value"]',
166+
(element) => element.textContent,
167+
);
168+
expect(proposedEndDateValue).toBe('5-11-2023');
169+
170+
const descriptionTextHeading = await page.$eval(
171+
'[data-modal-description-text="proposed-description-text"]',
172+
(element) => element.textContent,
173+
);
174+
expect(descriptionTextHeading).toBe('Description:');
175+
176+
const descriptionHtmlValue = await page.$eval(
177+
'[data-modal-description-value="proposed-description-value"]',
178+
(element) => element.innerHTML,
179+
);
180+
expect(descriptionHtmlValue).toContain('<h3 id="heading">Heading</h3>');
181+
});
182+
183+
it('Should contain Approve and Reject buttons', async function () {
184+
const approveButton = await page.$('.requestors__conatainer__list__button');
185+
const rejectButton = await page.$('.request-details__reject__button');
186+
expect(approveButton).toBeTruthy();
187+
expect(rejectButton).toBeTruthy();
188+
});
189+
});
190+
100191
describe('Task request details page with status creation', () => {
101192
let browser;
102193
let page;

mock-data/taskRequests/index.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,34 @@ const individualTaskReqDetail = {
6464
},
6565
};
6666

67+
const individualTaskReqDetailWithMarkDownInDescription = {
68+
message: 'Task request returned successfully',
69+
data: {
70+
createdAt: 1698837978463,
71+
lastModifiedAt: 1698837978463,
72+
requestType: 'ASSIGNMENT',
73+
createdBy: 'randhir',
74+
lastModifiedBy: 'randhir',
75+
taskTitle: 'sample golang task s402',
76+
externalIssueUrl:
77+
'https://api.github.com/repos/Real-Dev-Squad/website-backend/issues/1310',
78+
taskId: '44SwDPe1r6AgoOtWq8EN',
79+
users: [
80+
{
81+
proposedStartDate: 1698684354000,
82+
proposedDeadline: 1699142400000,
83+
description: '### Heading',
84+
markdownEnabled: true,
85+
userId: 'SooJK37gzjIZfFNH0tlL',
86+
status: 'PENDING',
87+
},
88+
],
89+
status: 'PENDING',
90+
id: 'dM5wwD9QsiTzi7eG7Oq6',
91+
url: 'http://localhost:3000/taskRequests/dM5wwD9QsiTzi7eG7Oq6',
92+
},
93+
};
94+
6795
const taskDetailCreation = {
6896
message: 'Task request returned successfully',
6997
data: {
@@ -325,8 +353,12 @@ const defaultMockResponseHeaders = {
325353
const urlMappings = {
326354
'https://api.realdevsquad.com/taskRequests/dM5wwD9QsiTzi7eG7Oq5':
327355
individualTaskReqDetail,
356+
'https://api.realdevsquad.com/taskRequests/dM5wwD9QsiTzi7eG7Oq6':
357+
individualTaskReqDetailWithMarkDownInDescription,
328358
'https://staging-api.realdevsquad.com/taskRequests/dM5wwD9QsiTzi7eG7Oq5':
329359
individualTaskReqDetail,
360+
'https://staging-api.realdevsquad.com/taskRequests/dM5wwD9QsiTzi7eG7Oq6':
361+
individualTaskReqDetailWithMarkDownInDescription,
330362
'https://api.realdevsquad.com/tasks/44SwDPe1r6AgoOtWq8EN/details':
331363
individualTaskDetail,
332364
'https://staging-api.realdevsquad.com/tasks/44SwDPe1r6AgoOtWq8EN/details':

task-requests/details/index.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@
1818
<script src="/task-requests/util.js"></script>
1919
<script src="/task-requests/constants.js"></script>
2020
<script src="/utils/time/index.js"></script>
21+
<script
22+
src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.0.11/purify.min.js"
23+
integrity="sha512-ce0fmuEgWrpnIXWKQrSgJ5FsBsr/hnOsxdWvk5lu1GThckasLwc+TAFERLNIwWnWqBoWV4GPDJiz2PSPntinVA=="
24+
crossorigin="anonymous"
25+
referrerpolicy="no-referrer"
26+
></script>
2127
<script src="/task-requests/details/script.js" defer></script>
2228
<script
2329
src="https://cdnjs.cloudflare.com/ajax/libs/showdown/2.1.0/showdown.min.js"

task-requests/details/script.js

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,8 @@ const renderGithubIssue = async () => {
342342
],
343343
}),
344344
);
345-
html = converter.makeHtml(res?.body);
345+
const body = DOMPurify.sanitize(res?.body ?? '');
346+
html = converter.makeHtml(body);
346347
taskContainer.appendChild(
347348
createCustomElement({
348349
tagName: 'div',
@@ -564,7 +565,23 @@ function populateModalContent(index) {
564565
'data-modal-description-value',
565566
'proposed-description-value',
566567
);
567-
descriptionValue.textContent = userData.description;
568+
569+
if (userData?.markdownEnabled ?? false) {
570+
converter = new showdown.Converter({
571+
tables: true,
572+
simplifiedAutoLink: true,
573+
tasklists: true,
574+
simplifiedAutoLink: true,
575+
ghCodeBlocks: true,
576+
openLinksInNewWindow: true,
577+
});
578+
const sanitizedDescription = DOMPurify.sanitize(userData.description ?? '');
579+
html = converter.makeHtml(sanitizedDescription);
580+
descriptionValue.innerHTML = html;
581+
descriptionValue.className = 'requestor_description_details';
582+
} else {
583+
descriptionValue.textContent = userData.description;
584+
}
568585

569586
const header = document.createElement('h2');
570587
header.setAttribute('data-modal-header', 'requestor-details-header');

task-requests/details/style.css

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,32 @@ table tr td {
481481
text-align: center;
482482
right: 10%;
483483
border-radius: 1rem;
484+
text-wrap: wrap;
485+
word-break: break-word;
486+
}
487+
488+
.requestor_description_details {
489+
background-color: var(--color-light-gray);
490+
width: 100%;
491+
text-align: left;
492+
text-wrap: wrap;
493+
word-break: break-word;
494+
}
495+
496+
.requestor_description_details h1 {
497+
font-size: 1.2rem;
498+
}
499+
500+
.requestor_description_details table th,
501+
.requestor_description_details table td {
502+
border: 1px solid gray;
503+
padding: 0.5rem;
504+
}
505+
506+
.requestor_description_details code,
507+
.requestor_description_details pre {
508+
font-family: consolas, monospace;
509+
white-space: normal;
484510
}
485511

486512
.requestor_details_modal_close {

0 commit comments

Comments
 (0)