Automatically highlights and selects the correct answer for every question on Quizlet test mode. Supports multiple choice and written question types. Works across all questions simultaneously.
// ==UserScript==
// @name Quizlet Test Auto Answer
// @namespace http://tampermonkey.net/
// @version 1.0
// @description Automatically highlights and selects the correct answer for every question on Quizlet test mode. Supports multiple choice and written question types. Works across all questions simultaneously.
// @author apzn
// @license MIT
// @match https://quizlet.com/*
// @grant unsafeWindow
// @run-at document-idle
// ==/UserScript==
const win = unsafeWindow;
function runOnArticles() {
win.document.querySelectorAll('article').forEach(element => {
const fiberKey = Object.keys(element).find(k => k.startsWith('__reactFiber$'));
if (!fiberKey) return;
let node = element[fiberKey];
let question = null;
while (node) {
if (node.memoizedProps?.question?.type) {
question = node.memoizedProps.question;
break;
}
node = node.return;
}
if (!question) return;
if (question.type === 'MultipleChoiceQuestion') {
const answerIndex = question.metadata.optionGenerationSource.findIndex(k => k === 'key');
const container = element.querySelector('[data-testid="MCQ Answers"]');
if (!container) return;
const wrapper = container.children[answerIndex];
if (!wrapper) return;
const answerText = wrapper.querySelector('section > :nth-child(2)');
if (answerText && answerText.style.color === 'lime') return;
[...container.children].forEach(child => {
const sec = child.querySelector('section > :nth-child(2)');
if (sec) sec.style.color = '';
});
if (answerText) answerText.style.color = 'lime';
const section = wrapper.querySelector('section') || wrapper;
if (section) {
const rect = section.getBoundingClientRect();
section.dispatchEvent(new PointerEvent('pointerdown', { bubbles: true, clientX: rect.x + 10, clientY: rect.y + 10 }));
section.dispatchEvent(new PointerEvent('pointerup', { bubbles: true, clientX: rect.x + 10, clientY: rect.y + 10 }));
section.dispatchEvent(new MouseEvent('click', { bubbles: true, clientX: rect.x + 10, clientY: rect.y + 10 }));
}
} else if (question.type === 'WrittenQuestion') {
if (typeof win.__NEXT_DATA__ === 'undefined') return;
const allCards = win.__NEXT_DATA__.props.pageProps.studyModesCommon.studiableDocumentData.studiableItems;
const card = allCards.find(c => c.id === question.metadata.studiableItemId);
if (!card) return;
const otherSide = card.cardSides[question.metadata.answerSide === 'definition' ? 1 : 0];
const answer = otherSide.media[0].plainText;
const existing = element.querySelector('#x-answer');
if (existing) return;
const form = element.querySelector('form');
if (form) form.parentElement.insertAdjacentHTML('afterbegin', `<p style="color:lime;padding-bottom:10px;" id="x-answer">correct answer: ${answer}</p>`);
const input = element.querySelector('form input, form textarea');
if (input && input.value !== answer) {
const setter = Object.getOwnPropertyDescriptor(win.HTMLInputElement.prototype, 'value')?.set
|| Object.getOwnPropertyDescriptor(win.HTMLTextAreaElement.prototype, 'value')?.set;
setter.call(input, answer);
input.dispatchEvent(new Event('input', { bubbles: true }));
}
}
});
}
const observer = new MutationObserver(() => {
if (win.document.querySelector('article')) {
setInterval(runOnArticles, 100);
observer.disconnect();
}
});
observer.observe(win.document.body, { childList: true, subtree: true });