Thursday, July 4, 2024

Easy install and update software on Windows with Chocolatey

Chocolatey provides a way similar to APT in Linux to download and update software on a Windows machine.

Here's how to install it: https://chocolatey.org/install

And here are the available packages: https://community.chocolatey.org/packages

And here's an example of installing some basic software:

choco install totalcommander googlechrome firefox notepadplusplus zoom vlc

Tuesday, April 27, 2021

Javascript Tips and Tricks

  • It is not possible to reassign an argument in a method. (a) => { a = 2; } will not work.
    However, it is possible to reassign a property of an argument object in a method, so (a) => { a.value = 2; } will work.
  • Promise execution has a different queue than normal code. This can be important in testing async code: in the test we'll have to make sure the test execution waits for the promise to resolve, before testing the return value or side effect.
  • Optional chaining saves you the trouble of testing for undefined keys in nested objects. Eg. person.address?.street?.name 
  • Use a variable's value as a key in and object with this syntax: { [yourKeyVariable]: someValue } 
  • ...

Testing a function with setTimeout and promises in Jest in Javascript

Inspiration for the code taken from Jest timer mocks documentation

Given a function that has both async/await and timeout, to test it with Jest, we need to know the following:
  • use jest.useFakeTimers() to get control of the timing
  • for each timeout, use the Jest Timer Control that applies
    • jest.runAllTimers() -- Fast-forward until all timers have been executed
    • jest.runOnlyPendingTimers() -- Fast forward and exhaust only currently pending timers (but not any new timers that get created during that process)
    • jest.advanceTimersByTime(1000) -- Fast-forward the given amount of milliseconds
  • for each await in the tested function, add await Promise.resolve() in the test, or any other way to resolve the promise before the test execution continues


The function to be tested:
async function infiniteAsyncTimerGame (beginningCallback, endingCallback) {
	console.log('start round');
	beginningCallback && await beginningCallback();
	console.log('awaited beginningCallback, will now set timeout');
	setTimeout(async () => {
		console.log('continuing after timeout');
		endingCallback && await endingCallback();
		console.log('awaited endingCallback, will now call function again');
		infiniteAsyncTimerGame(beginningCallback, endingCallback);
	}, 10000);
	console.log('end round');
}
The test:
test('infiniteAsyncTimerGame', async () => {
	// Preparations
	jest.useFakeTimers();

	let beginCounter = 0;
	let endCounter = 0;

	async function beginningCallback () {
		await new Promise(resolve => resolve(++beginCounter));
	}

	async function endingCallback () {
		await new Promise(resolve => resolve(++endCounter));
	}

	// Begin testing
	// notice the await keyword in front of the method call
	await infiniteAsyncTimerGame(beginningCallback, endingCallback);

	// At this point in time, there should have been a call to beginningCallback
	// We need to trigger the processing of each `await` keyword in the tested code
	// with `await Promise.resolve()` in the test run to flush the Promise queue
	// after that we can check for the value the Promise returned
	await Promise.resolve();
	console.log('check beginCounter');
	expect(beginCounter).toEqual(1);
	// After the beginningCallback, there should have been a single call to
	// setTimeout to schedule the next round in 10 seconds
	console.log('check timeout');
	expect(setTimeout).toHaveBeenCalledTimes(1);
	expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 10000);

	// Fast forward and exhaust only currently pending timers
	// (but not any new timers that get created during that process)
	console.log('runOnlyPendingTimers');
	jest.runOnlyPendingTimers();

	// At this point in time, there should have been a call to endingCallback
	await Promise.resolve();
	console.log('check endCounter');
	expect(endCounter).toEqual(1);

	// After the endingCallback, the next round should be started
	// with a new call to beginningCallback
	await Promise.resolve();
	console.log('check beginCounter');
	expect(beginCounter).toEqual(2);
	console.log('check timeout');
	expect(setTimeout).toHaveBeenCalledTimes(2);
	expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 10000);
	console.log('runOnlyPendingTimers');
	jest.runOnlyPendingTimers();
	await Promise.resolve();
	console.log('check endCounter');
	expect(endCounter).toEqual(2);

	// third round
	await Promise.resolve();
	console.log('check beginCounter');
	expect(beginCounter).toEqual(3);
	console.log('check timeout');
	expect(setTimeout).toHaveBeenCalledTimes(3);
	expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 10000);
	console.log('runOnlyPendingTimers');
	jest.runOnlyPendingTimers();
	await Promise.resolve();
	console.log('check endCounter');
	expect(endCounter).toEqual(3);
});

Monday, April 26, 2021

Testing the value of promises in Javascript without using Promise

Source: https://stackoverflow.com/a/54029876/4456532

Use case: when testing a code in Jest that already uses promises, I didn't want to use Promise resolve to peek into the promise, in order to not mess up the function execution. 

My helper function:
function promiseValue(p) {
	return process.binding('util').getPromiseDetails(p)[1];
}
Test for it with Jest:
test('promiseValue', () => {
	expect(promiseValue(new Promise(()=>{}))).toEqual(undefined);
	expect(promiseValue(Promise.resolve(2))).toEqual(2);
	expect(promiseValue(Promise.reject(0))).toEqual(0);
})

Testing the state of promises in JavaScript without using Promise

Relevant posts:

Use case: I would like to test a code with Jest that already uses promises, so to not mess up the promise queue, I needed a way to peek into the promise without using Promise.resolve or Promise.race.

My helper function:
const PROMISE_STATUS = Object.freeze({
	PENDING: 'pending',
	FULFILLED: 'fulfilled',
	REJECTED: 'rejected'
})

function promiseStatus(p) {
	if (inspect(p).includes(PROMISE_STATUS.PENDING)) {
		return PROMISE_STATUS.PENDING;
	}
	else if (inspect(p).includes(PROMISE_STATUS.REJECTED)) {
		return PROMISE_STATUS.REJECTED;
	}
	else {
		return PROMISE_STATUS.FULFILLED;
	}
}
Test for it with Jest:
test('promiseStatus', () => {
	expect(promiseStatus(new Promise(()=>{}))).toEqual(PROMISE_STATUS.PENDING);
	expect(promiseStatus(Promise.resolve(2))).toEqual(PROMISE_STATUS.FULFILLED);
	expect(promiseStatus(Promise.reject(0))).toEqual(PROMISE_STATUS.REJECTED);
})

Wednesday, February 17, 2021

Bash: String manipulation

For this example string: 
my_string="example.string.with.dots"
%: Remove match from last occurrence
echo "${my_string%.*}" # --> example.string.with
%%: Remove match from first occurrence
echo "${my_string%%.*}" # --> example
#: Remove match until first occurrence
echo "${my_string#*.}" # --> string.with.dots
##: Remove match until last occurrence
echo "${my_string##*.}" # --> dots
/n/n: Substitute one occurrence of the longest possible match
echo "${my_string/*./,}" # --> ,dots
//n/n: Substitute all occurrences of the longest possible match
echo "${my_string//?./,}" # --> exampl,strin,wit,dots
source: Baeldung


Sunday, December 6, 2020

Learn the concept of HTML and CSS in 5 minutes

HTML

Lesson:
  • We can imagine a HTML document as a series of boxes
  • Inside each box, there can be text and other boxes
  • There is one root box for the visual elements: the body box
  • The official name for the boxes is element
  • There are different types of elements, that can be used for different purposes
Good to know:
  • Using the elements according to their original purpose is generally a good practice and also helps with web accessibility
Exercise: explore the Elements panel of your browser's Developer tools. (Usually opens with F12, or you can reach it via "Inspect this element" from the right click menu on any page.)

CSS

Lesson:
  • To style an HTML element, we can put the styling directly into the element's style attribute (this is called inline styling)
  • To reuse styling across elements, we must mark elements that should be styled in the same way, and also extract the styling to a common place.
  • There are multiple ways to mark an element for styling:
    • for marking unique elements: provide an id attribute
    • for marking non-unique elements or grouping elements together based on a common attribute: provide one or more class attributes
    • for more fine-tuned styling, we can use other attributes than class (like data-*) as well to identify a certain element.
    • the type of elements (like div) can also be used to identify elements for styling, but it's less flexible compared to the class attribute.
  • These marks that enable selecting an element for styling are called CSS Selectors
  • The common place the styling is extracted to can be within a style tag or a separate file
  • To sum it up: CSS is these two things: the selectors and the styling together
Good to know:
  • CSS Selectors can be used for selecting elements on a page for other purpuses as well (like testing or interactive behavior)
  • Browsers provide default styling for the HTML elements
  • Not all styles can be applied to all elements
  • Not all styles are supported by all browsers
  • In case of clashing styles:
    • The style with the more specific selector for a given element will win
    • The style that was loaded later will win
Best Practice:
  • Consider separate classes for styling the look (eg. has no margin) and behavior (eg. primary button)
  • It is not recommended to use the id attribute unless you can guarantee that there will be no other element with the same id on the whole webpage (including embedded content)
  • It is not recommended to use inline styling
  • It is recommended to use relative units for sizing (eg. rem instead of px)
Exercise: open your browser's Developer tools and take a look at the Styles tab (usually on the right side) on the Elements panel. Play around with adding or removing styles, and observe which selectors affect the elements of the page. Check out the Computed tab as well.