- 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 }
- ...
Alice@Development
The purpose of this blog is to collect my knowledge on software development.
Tuesday, April 27, 2021
Javascript Tips and Tricks
Testing a function with setTimeout and promises in Jest in Javascript
- 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 executedjest.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, addawait Promise.resolve()
in the test, or any other way to resolve the promise before the test execution continues
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
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:
- How to check if a Promise is pending [duplicate]
- How can I synchronously determine a JavaScript Promise's state?
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
my_string="example.string.with.dots"
echo "${my_string%.*}" # --> example.string.with
%%: Remove match from first occurrenceecho "${my_string%%.*}" # --> example
#: Remove match until first occurrenceecho "${my_string#*.}" # --> string.with.dots
##: Remove match until last occurrenceecho "${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
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
- Using the elements according to their original purpose is generally a good practice and also helps with web accessibility
CSS
- To style an HTML element, we can put the styling directly into the element's style attribute (this is called inline styling)
- See CSS reference on MDN for the styling possibilities
- 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
- 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
- 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)
Note: Functional Interfaces in Java
(source: Java SE 8 for the Really Impatient: Programming with Lambdas - 3.3. Choosing a Functional Interface)
Common Functional Interfaces
Functional Interface |
Parameter Types |
Return Type |
Abstract Method Name |
Description |
Other Methods |
|
none |
|
|
Runs an action without arguments or return value |
|
|
none |
|
|
Supplies a value of type |
|
|
|
|
|
Consumes a value of type |
|
|
|
|
|
Consumes values of types |
|
|
|
|
|
A function with argument of type |
|
|
|
|
|
A function with arguments of types |
|
|
|
|
|
A unary operator on the type |
|
|
|
|
|
A binary operator on the type |
|
|
|
|
|
A Boolean-valued function |
|
|
|
|
|
A Boolean-valued function with two arguments |
|
Functional Interfaces for Primitive Types
p, q is int
, long
, double
; P, Q is Int
, Long
, Double
Functional Interface |
Parameter Types |
Return Type |
Abstract Method Name |
|
none |
|
|
P |
none |
p |
|
P |
p |
|
|
|
|
|
|
P |
p |
|
|
P |
p |
q |
|
|
|
p |
|
|
|
p |
|
P |
p |
p |
|
P |
p, p |
p |
|
P |
p |
|
|