Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Stryker Mutator for Mutation Testing and Debugging CopyFile Issue #23

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,6 @@ link-plugins.sh
test.sh

.docker/**
!**/.gitkeep
!**/.gitkeep
# stryker temp files
.stryker-tmp
3 changes: 3 additions & 0 deletions .strykerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
build/
public/
plugins/
Binary file modified dump.rdb
Binary file not shown.
7 changes: 6 additions & 1 deletion nodebb-theme-harmony/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@
{ "hook": "filter:teasers.configureStripTags", "method": "filterTeasersConfigureStripTags"}
],
"scripts": [
"public/harmony.js"
"public/harmony.js",
"public/darkmode.js",
"public/styles/darkmode.css"
],
"css": [
"public/styles/darkmode.css"
],
"modules": {
"../admin/plugins/harmony.js": "public/admin.js",
Expand Down
37 changes: 37 additions & 0 deletions nodebb-theme-harmony/public/darkmode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// $(document).ready(function () {
// // Check user's saved preference and apply dark mode
// if (config.user && config.user.settings.darkMode) {
// $('body').addClass('dark-mode');
// $('#darkModeToggle').prop('checked', true);
// }

// // Toggle dark mode when user changes the setting
// $('#darkModeToggle').change(function () {
// const isDarkMode = $(this).prop('checked');
// $('body').toggleClass('dark-mode', isDarkMode);
// $.post('/api/user/settings', { darkMode: isDarkMode ? '1' : '0' });
// });
// });

document.addEventListener("DOMContentLoaded", function () {
const darkModeToggle = document.getElementById("darkModeToggle");

function applyDarkMode(isEnabled) {
if (isEnabled) {
document.body.classList.add("dark-mode");
localStorage.setItem("darkMode", "true");
} else {
document.body.classList.remove("dark-mode");
localStorage.setItem("darkMode", "false");
}
}

// Load setting from local storage
applyDarkMode(localStorage.getItem("darkMode") === "true");

if (darkModeToggle) {
darkModeToggle.addEventListener("change", function () {
applyDarkMode(this.checked);
});
}
});
22 changes: 22 additions & 0 deletions nodebb-theme-harmony/public/harmony.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,28 @@ $(document).ready(function () {
fixPlaceholders();
fixSidebarOverflow();

const darkModeToggle = document.getElementById("darkModeToggle");

if (darkModeToggle) {
// Apply stored preference
if (localStorage.getItem("darkMode") === "enabled") {
document.body.classList.add("dark-mode");
darkModeToggle.checked = true;
}

// Listen for changes
darkModeToggle.addEventListener("change", function () {
if (this.checked) {
document.body.classList.add("dark-mode");
localStorage.setItem("darkMode", "enabled");
} else {
document.body.classList.remove("dark-mode");
localStorage.setItem("darkMode", "disabled");
}
});
}


function setupSkinSwitcher() {
$('[component="skinSwitcher"]').on('click', '.dropdown-item', function () {
const skin = $(this).attr('data-value');
Expand Down
13 changes: 13 additions & 0 deletions nodebb-theme-harmony/templates/account/settings.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,19 @@

<h6 class="fw-bold">[[user:browsing]]</h6>


<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="openOutgoingLinksInNewTab" data-property="openOutgoingLinksInNewTab" {{{ if settings.openOutgoingLinksInNewTab }}}checked{{{ end }}}/>
<label class="form-check-label text-sm" for="openOutgoingLinksInNewTab">[[user:open-links-in-new-tab]]</label>
</div>

<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="darkModeToggle" data-property="darkMode" {{{ if settings.darkMode }}}checked{{{ end }}}/>
<label class="form-check-label text-sm" for="darkModeToggle">Enable Dark Mode</label>
</div>



{{{ if inTopicSearchAvailable }}}
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="topicSearchEnabled" data-property="topicSearchEnabled" {{{ if settings.topicSearchEnabled }}}checked{{{ end }}}/>
Expand All @@ -92,6 +100,11 @@

<h6 class="fw-bold">[[global:pagination]]</h6>

<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="darkModeToggle" data-property="darkMode" {{{ if settings.darkMode }}}checked{{{ end }}}/>
<label class="form-check-label text-sm" for="darkModeToggle">Enable Dark Mode</label>
</div>

<div class="mb-2 form-check form-switch">
<input type="checkbox" role="switch" id="usePagination" class="form-check-input" data-property="usePagination" {{{ if settings.usePagination }}}checked{{{ end }}}>
<label class="form-check-label text-sm" for="usePagination">[[user:paginate-description]]</label>
Expand Down
7 changes: 7 additions & 0 deletions nodebb-theme-harmony/templates/account/theme.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,13 @@
</label>
</div>

<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" role="switch" id="darkModeToggle" name="darkMode" {{{ if theme.darkMode }}}checked{{{ end }}}>
<label class="form-check-label" for="darkModeToggle">
Enable Dark Mode
</label>
</div>

</form>

<!-- IMPORT partials/account/footer.tpl -->
6 changes: 5 additions & 1 deletion nodebb-theme-harmony/templates/partials/topic/post.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,11 @@
<div class="d-flex gap-1 align-items-center">
<span class="text-muted">{generateWroteReplied(@value, config.timeagoCutoff)}</span>

<i component="post/edit-indicator" class="fa fa-edit text-muted{{{ if privileges.posts:history }}} pointer{{{ end }}} edit-icon {{{ if !posts.editor.username }}}hidden{{{ end }}}" title="[[global:edited-timestamp, {isoTimeToLocaleString(./editedISO, config.userLang)}]]"></i>
<i component="post/edit-indicator" class="fa fa-edit text-muted{{{ if privileges.posts:history }}} pointer{{{ end }}} edit-icon"></i>
<span class="edited-time text-muted">
<i class="fa fa-clock"></i>
<span class="timeago" title="{isoTimeToLocaleString(posts.editedISO, config.userLang)}"></span>
</span>
<span data-editor="{posts.editor.userslug}" component="post/editor" class="visually-hidden">[[global:last-edited-by, {posts.editor.username}]] <span class="timeago" title="{isoTimeToLocaleString(posts.editedISO, config.userLang)}"></span></span>
</div>

Expand Down
30 changes: 26 additions & 4 deletions src/cli/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,21 +103,43 @@ global.env = process.env.NODE_ENV || 'production';
prestart.setupWinston();

// Alternate configuration file support
// const configFile = path.resolve(paths.baseDir, nconf.get('config') || 'config.json');
// const configExists = file.existsSync(configFile) || (nconf.get('url') && nconf.get('secret') && nconf.get('database'));

// prestart.loadConfig(configFile);
// prestart.versionCheck();

// if (!configExists && process.argv[2] !== 'setup') {
// require('./setup').webInstall();
// return;
// }

// if (configExists) {
// process.env.CONFIG = configFile;
// }


//code change by evelyn
const configFile = path.resolve(paths.baseDir, nconf.get('config') || 'config.json');
const configExists = file.existsSync(configFile) || (nconf.get('url') && nconf.get('secret') && nconf.get('database'));

prestart.loadConfig(configFile);
prestart.versionCheck();

if (!configExists && process.argv[2] !== 'setup') {
require('./setup').webInstall();
return;
function checkAndSetup() {
if (!configExists && process.argv[2] !== 'setup') {
require('./setup').webInstall();
return; // ✅ Now inside a function, so no syntax error
}
}

checkAndSetup();

if (configExists) {
process.env.CONFIG = configFile;
process.env.CONFIG = configFile;
}


// running commands
program
.command('start')
Expand Down
7 changes: 6 additions & 1 deletion src/user/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ module.exports = function (User) {
let settings = await db.getObject(`user:${uid}:settings`);
settings = settings || {};
settings.uid = uid;
settings.darkMode = settings.darkMode || false; // Retrieve dark mode setting
return await onSettingsLoaded(uid, settings);
};


User.getMultipleUserSettings = async function (uids) {
if (!Array.isArray(uids) || !uids.length) {
Expand Down Expand Up @@ -148,6 +150,7 @@ module.exports = function (User) {
categoryWatchState: data.categoryWatchState,
categoryTopicSort: data.categoryTopicSort,
topicPostSort: data.topicPostSort,
darkMode: data.darkMode || false, // Save dark mode preference
};
const notificationTypes = await notifications.getAllNotificationTypes();
notificationTypes.forEach((notificationType) => {
Expand All @@ -172,7 +175,9 @@ module.exports = function (User) {
if (parseInt(uid, 10) <= 0) {
return;
}

if (key === 'darkMode') {
value = value ? true : false; // Ensure it's a boolean
}
await db.setObjectField(`user:${uid}:settings`, key, value);
};
};
21 changes: 21 additions & 0 deletions stryker.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"$schema": "./node_modules/@stryker-mutator/core/schema/stryker-schema.json",
"packageManager": "npm",
"reporters": [
"html",
"clear-text",
"progress"
],
"testRunner": "mocha",
"coverageAnalysis": "perTest",
"mutate": [
"src/**/*.js"
],
"sandbox": {
"filePatterns": [
"!build/**",
"!public/**",
"!plugins/**"
]
}
}
23 changes: 23 additions & 0 deletions stryker_output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
14:23:35 (34493) WARN OptionsValidator Unknown stryker config option "sandbox".
14:23:35 (34493) WARN OptionsValidator Possible causes:
* Is it a typo on your end?
* Did you only write this property as a comment? If so, please postfix it with "_comment".
* You might be missing a plugin that is supposed to use it. Stryker loaded plugins from: ["@stryker-mutator/*"]
* The plugin that is using it did not contribute explicit validation.
(disable "warnings.unknownOptions" to ignore this warning)
14:23:35 (34493) INFO ProjectReader Found 548 of 10828 file(s) to be mutated.
14:23:38 (34493) INFO Instrumenter Instrumented 548 source file(s) with 55842 mutant(s)
14:23:39 (34493) INFO ConcurrencyTokenProvider Creating 7 test runner process(es).
14:23:40 (34493) ERROR Stryker Unexpected error occurred while running Stryker Error: ENOTSUP: operation not supported on socket, copyfile '/Users/evelynlo/nodebb-s25-puffers/build/public/plugins/nodebb-plugin-markdown/styles' -> '/Users/evelynlo/nodebb-s25-puffers/.stryker-tmp/sandbox-oxK0Gt/build/public/plugins/nodebb-plugin-markdown/styles'
at async Object.copyFile (node:internal/fs/promises:621:10)
at async FileSystemAction.execute (file:///Users/evelynlo/nodebb-s25-puffers/node_modules/@stryker-mutator/core/dist/src/fs/file-system.js:16:28)
at async file:///Users/evelynlo/nodebb-s25-puffers/node_modules/@stryker-mutator/core/dist/src/fs/file-system.js:33:9 {
errno: -45,
code: 'ENOTSUP',
syscall: 'copyfile',
path: '/Users/evelynlo/nodebb-s25-puffers/build/public/plugins/nodebb-plugin-markdown/styles',
dest: '/Users/evelynlo/nodebb-s25-puffers/.stryker-tmp/sandbox-oxK0Gt/build/public/plugins/nodebb-plugin-markdown/styles'
}
14:23:40 (34493) INFO Stryker This might be a known problem with a solution documented in our troubleshooting guide.
14:23:40 (34493) INFO Stryker You can find it at https://stryker-mutator.io/docs/stryker-js/troubleshooting/
14:23:40 (34493) INFO Stryker Still having trouble figuring out what went wrong? Try `npx stryker run --fileLogLevel trace --logLevel debug` to get some more info.