Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 10 additions & 16 deletions core/scripts/crispr_scripts.js
Original file line number Diff line number Diff line change
Expand Up @@ -692,12 +692,12 @@ function showFeedback() {
append_str += "<div class='card-header' id='gRNACard'>";
append_str += "<h5 class='mb-0'>";
append_str +=
"<button class='btn btn-link' data-toggle='collapse' data-target='#gRNAOutput' aria-expanded='false' aria-controls='gRNAOutput'>";
"<button class='btn btn-link' data-bs-toggle='collapse' data-bs-target='#gRNAOutput' aria-expanded='false' aria-controls='gRNAOutput'>";
append_str += `gRNA Strand Sequence: ${MARgRNAseq_degree_display}/2`;
append_str += "</button>";
append_str += "</h5>";
append_str += "</div>";
append_str += "<div id='gRNAOutput' class='collapse' aria-labelledby='headingOne' data-parent='#accordion'>";
append_str += "<div id='gRNAOutput' class='collapse' aria-labelledby='gRNACard'>";
append_str += "<div class='card-body'>";
// Content
append_str += `<p> For gRNA Strand Sequence, you put down "${all_answers[0]}" which gave you the mark ${MARgRNAseq_degree_display}.</p>`;
Expand All @@ -713,12 +713,12 @@ function showFeedback() {
append_str += "<div class='card-header' id='PAMCard'>";
append_str += "<h5 class='mb-0'>";
append_str +=
"<button class='btn btn-link' data-toggle='collapse' data-target='#PAMOutput' aria-expanded='false' aria-controls='PAMOutput'>";
"<button class='btn btn-link' data-bs-toggle='collapse' data-bs-target='#PAMOutput' aria-expanded='false' aria-controls='PAMOutput'>";
append_str += `gRNA PAM Sequence: ${MARPAMseq_display}/2`;
append_str += "</button>";
append_str += "</h5>";
append_str += "</div>";
append_str += "<div id='PAMOutput' class='collapse' aria-labelledby='headingOne' data-parent='#accordion'>";
append_str += "<div id='PAMOutput' class='collapse' aria-labelledby='PAMCard'>";
append_str += "<div class='card-body'>";
// Content
append_str += `<p> For gRNA PAM Sequence, you put down "${all_answers[1]}" which gave you the mark ${MARPAMseq_display}.</p>`;
Expand All @@ -734,12 +734,12 @@ function showFeedback() {
append_str += "<div class='card-header' id='OffTargetCard'>";
append_str += "<h5 class='mb-0'>";
append_str +=
"<button class='btn btn-link' data-toggle='collapse' data-target='#OffTargetOutput' aria-expanded='false' aria-controls='OffTargetOutput'>";
"<button class='btn btn-link' data-bs-toggle='collapse' data-bs-target='#OffTargetOutput' aria-expanded='false' aria-controls='OffTargetOutput'>";
append_str += `Off-target Score: ${MAROffTarget_degree_display}/2`;
append_str += "</button>";
append_str += "</h5>";
append_str += "</div>";
append_str += "<div id='OffTargetOutput' class='collapse' aria-labelledby='headingOne' data-parent='#accordion'>";
append_str += "<div id='OffTargetOutput' class='collapse' aria-labelledby='OffTargetCard'>";
append_str += "<div class='card-body'>";
// Content
append_str += `<p> For Off-Target Score, you put down "${all_answers[4]}" which gave you the mark ${MAROffTarget_degree_display}.</p>`;
Expand All @@ -755,12 +755,12 @@ function showFeedback() {
append_str += "<div class='card-header' id='F1PrimerCard'>";
append_str += "<h5 class='mb-0'>";
append_str +=
"<button class='btn btn-link' data-toggle='collapse' data-target='#F1PrimerOutput' aria-expanded='false' aria-controls='F1PrimerOutput'>";
"<button class='btn btn-link' data-bs-toggle='collapse' data-bs-target='#F1PrimerOutput' aria-expanded='false' aria-controls='F1PrimerOutput'>";
append_str += `F1 Primer: ${MARF1primers_display}/2`;
append_str += "</button>";
append_str += "</h5>";
append_str += "</div>";
append_str += "<div id='F1PrimerOutput' class='collapse' aria-labelledby='headingOne' data-parent='#accordion'>";
append_str += "<div id='F1PrimerOutput' class='collapse' aria-labelledby='F1PrimerCard'>";
append_str += "<div class='card-body'>";
// Content
append_str += `<p> For F1 Primer, you put down "${all_answers[5]}" which gave you the mark ${MARF1primers_display}.</p>`;
Expand All @@ -776,12 +776,12 @@ function showFeedback() {
append_str += "<div class='card-header' id='R1PrimerCard'>";
append_str += "<h5 class='mb-0'>";
append_str +=
"<button class='btn btn-link' data-toggle='collapse' data-target='#R1PrimerOutput' aria-expanded='false' aria-controls='R1PrimerOutput'>";
"<button class='btn btn-link' data-bs-toggle='collapse' data-bs-target='#R1PrimerOutput' aria-expanded='false' aria-controls='R1PrimerOutput'>";
append_str += `R1 Primer: ${MARR1primers_display}/2`;
append_str += "</button>";
append_str += "</h5>";
append_str += "</div>";
append_str += "<div id='R1PrimerOutput' class='collapse' aria-labelledby='headingOne' data-parent='#accordion'>";
append_str += "<div id='R1PrimerOutput' class='collapse' aria-labelledby='R1PrimerCard'>";
append_str += "<div class='card-body'>";
// Content
append_str += `<p> For R1 Primer, you put down "${all_answers[6]}" which gave you the mark ${MARR1primers_display}.</p>`;
Expand Down Expand Up @@ -856,13 +856,7 @@ function submitAnswers() {
);
all_marks.push(studentMark, studentMarkPercentage);

document.getElementById("options_label").innerHTML =
"Would you like to see feedback on your answers or start a new assignment?";
document.getElementById("seeFeedback").removeAttribute("hidden");

showFeedback();

$("#feedbackButton").click();
}, 750);
}

Expand Down
2 changes: 1 addition & 1 deletion core/scripts/crispr_scripts.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion core/scripts/serviceWorker/sw.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion core/scripts/serviceWorker/sw.js.map

Large diffs are not rendered by default.

66 changes: 0 additions & 66 deletions core/systemrun.html
Original file line number Diff line number Diff line change
Expand Up @@ -181,71 +181,5 @@
<a href="about.html" aria-hidden="true" hidden>About</a>
</nav>
<div class="container focusContainer" role="tabpanel" id="mainContainer"></div>

<!-- Feedback button -->
<button
id="feedbackButton"
type="button"
class="btn btn-primary"
data-toggle="modal"
data-target="#feedbackModal"
hidden
>
Open feedback modal
</button>
<div
class="modal fade"
id="feedbackModal"
tabindex="-1"
role="dialog"
aria-labelledby="feedbackModalLabel"
aria-hidden="true"
>
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="feedbackModalLabel">Done!</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body" id="feedbackBody">
<p id="FeedbackContent">Congratulations! Your answers have been submitted.</p>
<p id="options_label">
Would you like to see feedback on your answers or start a new assignment?
</p>
<p>
<button
type="button"
id="seeFeedback"
class="btn btn-primary"
onclick="
showFeedback();
$('#dismissFeedbackModal').click();
"
>
See Feedback
</button>
<button
type="button"
id="backAssignments"
class="btn btn-primary"
onclick="
backToAssignments();
$('#dismissFeedbackModal').click();
"
>
Back to Assignments
</button>
</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal" id="dismissFeedbackModal">
Close
</button>
</div>
</div>
</div>
</div>
</main>
</html>
4 changes: 2 additions & 2 deletions docs/architecture/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ Application styles covering:

- Layout and responsive design
- Form styling and validation states
- Feedback page appearance
- Modal dialogs used by feedback flows
- Feedback page appearance
- Feedback UI: rendered inline by `showFeedback()` in the runtime page (no modal dialogs are used; see [core/scripts/crispr_scripts.js](../../core/scripts/crispr_scripts.js) and [core/systemrun.html](../../core/systemrun.html)).

Built with Bootstrap utilities integrated via [core/scripts/APIandLibraries/Bootstrap/](../../core/scripts/APIandLibraries/Bootstrap/).

Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ SciGrade uses the gene list defined in [core/data/Background_info/gene_backgroun
#### Practice Flow

- The runtime page initializes the practice flow on page load
- Feedback is generated after submission by [core/scripts/crispr_scripts.js](../core/scripts/crispr_scripts.js)
- Feedback is generated after submission by [core/scripts/crispr_scripts.js](../core/scripts/crispr_scripts.js) and rendered inline by `showFeedback()`.

The [CHANGELOG.md](../CHANGELOG.md) records the deprecation of online account features.

Expand Down
2 changes: 1 addition & 1 deletion playwright.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export default defineConfig({
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: 2,
workers: 20,
workers: 15,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: [["list"], ["html"], ["json", { outputFile: "test-results/results.json" }]],
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
Expand Down
58 changes: 58 additions & 0 deletions tests/playwright/submission.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ test.describe("SciGrade Submission Flow", () => {

// Wait for the form to be generated (loadWork appends form inputs into #work)
await page.waitForSelector("#sequence_input", { state: "visible" });

// Wait for form to be fully rendered and interactive: submit button present and enabled
await page.waitForFunction(() => {
const btn = document.getElementById("assignmentSubmitButton");
return !!btn && !btn.disabled;
});
});

// Data-driven tests using test case table
Expand Down Expand Up @@ -80,4 +86,56 @@ test.describe("SciGrade Submission Flow", () => {
await expect(page.locator("body")).toContainText(/gRNA PAM Sequence/);
});
}

// Test for double submission in the same session
test("should allow submitting twice in the same session", async ({ page }) => {
// First submission
await page.fill("#sequence_input", "AAGCACTGCACGCCGTGGGT");
await page.selectOption("#strand_input", "Antisense (-)");
await page.fill("#pam_input", "CAG");
await page.fill("#position_input", "381");
await page.fill("#offtarget_input", "87");
await page.fill("#f1_input", "TAATACGACTCACTATAGAAGCACTGCACGCCGT");
await page.fill("#r1_input", "TTCTAGCTCTAAAACACCCACGGCGTGCAGTGCT");

// Click Submit button
await page.click("#assignmentSubmitButton");

// Wait for feedback to render
await expect(page.locator("body")).toContainText(/Mark:/, { timeout: 15000 });

// Return to assignments (simulates selecting a new assignment)
await page.click("button:has-text('Back to Assignments')");

// Wait for the form to be reset and visible again
await page.waitForSelector("#gene_dropdown_selection");

// Select gene again
await page.selectOption("#gene_dropdown_selection", "eBFP");
await page.getByRole("button", { name: "Load Gene" }).click();

// Wait for form to be ready
await page.waitForFunction(() => {
const btn = document.getElementById("assignmentSubmitButton");
return !!btn && !btn.disabled;
});

// Second submission with different values
await page.fill("#sequence_input", "AAAAAAAAAAAAAAAAAAAA");
await page.selectOption("#strand_input", "Sense (+)");
await page.fill("#pam_input", "AAA");
await page.fill("#position_input", "999");
await page.fill("#offtarget_input", "1");
await page.fill("#f1_input", "AAAAAAAAAAAAAAAAAAAA");
await page.fill("#r1_input", "TTTTTTTTTTTTTTTTTTTT");

// Click Submit button again
await page.click("#assignmentSubmitButton");

// Wait for feedback to render again
await expect(page.locator("body")).toContainText(/Mark:/, { timeout: 15000 });

// Verify feedback is displayed correctly
await expect(page.locator("body")).toContainText(/gRNA Strand Sequence/);
});
});