I want to start Cypress with consistent time, e.g. first Monday of July of current year. I can use clock to override current time:
cy.clock(new Date(2023, 7, 1, 12, 0, 0), ['Date']);
but then I'd have to use cy.tick whenever I want to simulate some time passing. Is there a way to set the initial time for tests but allow the time to flow on its own? So that 5 seconds after calling cy.clock it is "2023-07-01 12:00:05", not permanently "2023-07-01 12:00:00".
This should be easy, not sure why it isn't.
Here is a custom command and a proof-of-concept test to confirm it.
/cypress/support/commands.js
const FakeTimers = require("#sinonjs/fake-timers");
Cypress.Commands.add("setAppDate", (targetDate) => {
cy.window().then((win) => {
const clock = FakeTimers.withGlobal(win).install({
now: targetDate,
toFake: ["Date"],
shouldAdvanceTime: true,
advanceTimeDelta: 40,
});
});
})
Test
const targetDate = new Date(2023, 7, 1, 12, 0, 0)
cy.window()
.then((win) => {
const dateBefore = new win.Date()
expect(dateBefore).be.lt(targetDate) // app has date before targetDate
})
.setAppDate(targetDate)
.then((win) => {
const dateAfter = new win.Date();
expect(dateAfter).to.deep.eq(targetDate) // app date changed to targetDate
})
.wait(1000) // let some time go by
.then((win) => {
const afterWait = new win.Date();
expect(afterWait).to.be.gt(targetDate) // app date increased during wait
});
Results
Background
Looking at the source for cy.clock(), can see it is wrapping #sinonjs/fake-timers
import _ from 'lodash'
import fakeTimers from '#sinonjs/fake-timers'
const install = (win, now, methods) => {
return fakeTimers.withGlobal(win).install({
now,
toFake: methods,
})
}
#sinonjs/fake-timers has an option called shouldAdvanceTime
var clock = FakeTimers.install([config])
Parameter
Type
Default
Description
config.shouldAdvanceTime
Boolean
false
tells FakeTimers to increment mocked time automatically based on the real system time shift (e.g. the mocked time will be incremented by 20ms for every 20ms change in the real system time)
Unfortunately, cy.clock() does not expose that option, but you can use it directly in your specs via the custom command above.
Related
As I understand, in FRP (Functional Reactive Programming), we model the system as a component which receives some input signals and generates some output signals:
,------------.
--- input1$ --> | | -- output1$ -->
| System | -- output2$ -->
--- input2$ --> | | -- output3$ -->
`------------'
In this way, if we have multiple subsystems, we can plump them together as long as we can provide operators that can pipe inputs and outputs.
Now, I'm building an app, which processes video frames asynchronously. The actual processing logic is abstracted and can be provided as an argument. In non-FRP way of thinking, I can construct the app as
new App(async (frame) => {
return await processFrame(frame)
})
The App is responsible for establishing communication with underlying video pipeline and repeatedly get video frames and then pass that frame to the given callback, and once the callback resolves,App sends back the processed frame.
Now I want to model the App in a FRP way so I can flexibly design the frame processing.
const processedFrameSubject = new Subject()
const { frame$ } = createApp(processedFrameSubject)
frame$.pipe(
map(toRGB),
mergeMap(processRGBFrame),
map(toYUV)
).subscribe(processedFrameSubject)
The benefit is that it enables the consumer of createApp to define the processing pipeline declaratively.
However, in createApp, given a processedFrame, I need to reason about which frame it is related to. Since frame$ and processedFrameSubject is now separated, it's really hard for createApp to reason about which frame a processedFrame is related to, which was quite easy in non-FRP implementation because the frame and processedFrame were in same closure.
In functional reactive programming, you would avoid using side effects as much as possible, this means avoiding .subscribe(, tap(() => subject.next()), etc. With FRP, your state is declared on how it works and how it's wired up, but it doesn't execute until someone needs it and performs the side effect.
So I think that the following API would still be considered FRP:
function createApp(
processFrame: (frame: Frame) => Observable<ProcessedFrame>
): Observable<void>
const app$ = createApp(frame => of(frame).pipe(
map(toRGB),
mergeMap(processRGBFrame),
map(toYUV)
));
// `app$` is an Observable that can be consumed by composing it to other
// observables, or by "executing the side effect" by .subscribe() on it
// possible implementation of createApp for this API
function createApp(
processFrame: (frame: Frame) => Observable<ProcessedFrame>
) {
return new Observable<void>(() => {
const stopVideoHandler = registerVideoFrameHandler(
(frame: Frame) => firstValueFrom(processFrame(frame))
);
return () => {
// teardown
stopVideoHandler()
}
});
}
Something worth noting is that createApp is returning a new Observable. Inside new Observable( we can escape from FRP because it's the only way we can integrate with external parties, and all the side effects we have written won't be called until someone .subscribe()s to the observable.
This API is simple and would still be FRP, but it has one limitation: the processFrame callback can only process frames independently from others.
If you need an API that supports that, then you need to expose the frames$, but again, this is a project function for createApp:
function createApp(
projectFn: (frame$: Observable<Frame>) => Observable<ProcessedFrame>
): Observable<void>
const app$ = createApp(frame$ => frame$.pipe(
map(toRGB),
mergeMap(processRGBFrame),
map(toYUV)
));
// possible declaration of createApp
function createApp(
projectFn: (frame$: Observable<Frame>) => Observable<ProcessedFrame>
) {
return new Observable<void>(() => {
const frame$ = new Subject<Frame>;
const processedFrame$ = connectable(frame$.pipe(projectFn));
const processedSub = processedFrame$.connect();
const stopVideoHandler = registerVideoFrameHandler(
(frame: Frame) => {
// We need to create the promise _before_ we send in the next `frame$`, in case it's processed synchronously
const resultFrame = firstValueFrom(processedFrame$);
frame$.next(frame);
return resultFrame;
})
);
return () => {
// teardown
stopVideoHandler()
processedSub.unsubscribe();
}
});
}
I'm guessing here registerVideoFrameHandler will call the function one-by-one without overlap? If there's overlap then you'd need to track the frame number in some way, if the SDK doesn't give you any option, then try something like:
// Assuming `projectFn` will emit frames in order. If not, then the API
// should change to be able to match them
const processedFrame$ = connectable(frame$.pipe(
projectFn,
map((result, index) => ({ result, index }))
));
const processedSub = processedFrame$.connect();
let frameIdx = 0;
const stopVideoHandler = registerVideoFrameHandler(
(frame: Frame) => {
const thisIdx = frameIdx;
frameIdx++;
const resultFrame = firstValueFrom(processedFrame$.pipe(
filter(({ index }) => index === thisIdx),
map(({ result }) => result)
));
frame$.next(frame);
return resultFrame;
})
);
So I'm relatively inexperienced with rxjs so if this is something that would be a pain or really awkward to do, please tell me and I'll go a different route. So in this particular use case, I was to queue up updates to send to the server, but if there's an update "in flight" I want to only keep the latest item which will be sent when the current in flight request completes.
I am kind of at a loss of where to start honestly. It seems like this would be either a buffer type operator and/or a concat map.
Here's what I would expect to happen:
const updateQueue$ = new Subject<ISettings>()
function sendToServer (settings: ISettings): Observable {...}
...
// we should send this immediately because there's nothing in-flight
updateQueue$.next({ volume: 25 });
updateQueue$.next({ volume: 30 });
updateQueue$.next({ volume: 50 });
updateQueue$.next({ volume: 65 });
// lets assume that our our original update just completed
// I would now expect a new request to go out with `{ volume: 65 }` and the previous two to be ignored.
I think you can achieve what you want with this:
const allowNext$ = new Subject<boolean>()
const updateQueue$ = new Subject<ISettings>()
function sendToServer (settings: ISettings): Observable { ... }
updateQueue$
.pipe(
// Pass along flag to mark the first emitted value
map((value, index) => {
const isFirstValue = index === 0
return { value, isFirstValue }
}),
// Allow the first value through immediately
// Debounce the rest until subject emits
debounce(({ isFirstValue }) => isFirstValue ? of(true) : allowNext$),
// Send network request
switchMap(({ value }) => sendToServer(value)),
// Push to subject to allow next debounced value through
tap(() => allowNext$.next(true))
)
.subscribe(response => {
...
})
This is a pretty interesting question.
If you did not have the requirement of issuing the last in the queue, but simply ignoring all requests of update until the one on the fly completes, than you would simply have to use exhaustMap operator.
But the fact that you want to ignore all BUT the last request for update makes the potential solution a bit more complex.
If I understand the problem well, I would proceed as follows.
First of all I would define 2 Subjects, one that emits the values for the update operation (i.e. the one you have already defined) and one dedicated to emit only the last one in the queue if there is one.
The code would look like this
let lastUpdate: ISettings;
const _updateQueue$ = new Subject<ISettings>();
const updateQueue$ = _updateQueue$
.asObservable()
.pipe(tap(settings => (lastUpdate = settings)));
const _lastUpdate$ = new Subject<ISettings>();
const lastUpdate$ = _lastUpdate$.asObservable().pipe(
tap(() => (lastUpdate = null)),
delay(0)
);
Then I would merge the 2 Observables to obtain the stream you are looking for, like this
merge(updateQueue$, lastUpdate$)
.pipe(
exhaustMap(settings => sendToServer(settings))
)
.subscribe({
next: res => {
// do something with the response
if (lastUpdate) {
// emit only if there is a new "last one" in the queue
_lastUpdate$.next(lastUpdate);
}
},
});
You may notice that the variable lastUpdate is used to control that the last update in the queue is used only once.
Let's say I have a rather typical use of rx that does requests every time some change event comes in (I write this in the .NET style, but I'm really thinking of Javascript):
myChanges
.Throttle(200)
.Select(async data => {
await someLongRunningWriteRequest(data);
})
If the request takes longer than 200ms, there's a chance a new request begins before the old one is done - potentially even that the new request is completed first.
How to synchronize this?
Note that this has nothing to do with multithreading, and that's the only thing I could find information about when googling for "rx synchronization" or something similar.
You could use concatMap operator which will start working on the next item only after previous was completed.
Here is an example where events$ appear with the interval of 200ms and then processed successively with a different duration:
const { Observable } = Rx;
const fakeWriteRequest = data => {
console.log('started working on: ', data);
return Observable.of(data).delay(Math.random() * 2000);
}
const events$ = Observable.interval(200);
events$.take(10)
.concatMap(i => fakeWriteRequest(i))
.subscribe(e => console.log(e));
<script src="https://unpkg.com/rxjs/bundles/Rx.min.js"></script>
I've read several articals as well as offical docs of redux all of which mention mvc leads to non-deterministic ui while redux not as redux uses pure function. I know that pure function produces same output for same input. But why mutation does not? It would be nice to have an example.
Mutation + asynchronous code can easily lead to functions that don't return the same result given the same input. This is a (very) simplified example with some comments.
// this could be a function in your controller
function delayedAddition(valuePair) {
console.log(
`Getting ready to calculate ${valuePair.x} + ${valuePair.y}`
);
return new Promise((resolve, reject) => {
setTimeout(() => resolve(valuePair.x + valuePair.y), 500);
});
}
const printWithMessage = message => printMe => console.log(message, printMe);
let mutableValuePair = { x: 5, y: 10 };
// this could be a call your view depends on
delayedAddition(mutableValuePair)
.then(printWithMessage('Result is: '));
// MUTATION!
// This could happen in another controller,
// or where ever
mutableValuePair.x = 32;
// Expected result = 5 + 10.
// Result is: 42
// So your view is no longer a function of
// what arguments you pass to your controllers.
If we were using an immutable data structure for valuePair then something like valuePair.setX(32) would not change the original object. Instead we'd get back a new (independent) copy. So you would use it like this instead const modifiedValuePar = valuePair.setX(32). That way, the ongoing calculation (which used the unaffected valuePair) would still give the expected result that 5 + 10 = 15.
I have a problem which I don't know how to solve.
I have a component with an end-date, and I want to show a countdown timer with the remaining seconds.
I use moment JS for this, but I don't know how to implement this in Vue2.
Should I use a computed method?
computed: {
timer: function() {
var now = moment();
var then = moment().add(180, 'seconds');
return moment().to(then);
(function timerLoop() {
this.timer = countdown(then).toString();
requestAnimationFrame(timerLoop);
})();
},
Problem is that I have to return the value before vue2 shows it. But I also have to use requestAnimationFrame to update this every second.
Can anyone help me out? And what is the best way to use this? setInterval or requestAnimationFrame? I think the latter, because there will be 100+ timers on 1 page, so performance is necessary.
So long story, short:
Momentjs and countdown timer
How can I create an Vue2 function/method/mixin of this? And which updates every second?
Thanks
Instead of having a time-loop for each timer, I suggest having a single interval updating a value on the model every second and using Vue's reactivity to trigger updates to the computed properties.
I've created a pen where you easily can play around with number active timers to see how it impacts performance.
data() {
return {
interval: null,
now: new Date(),
dates: [], // Your dates here
}
},
computed() {
timers() {
return this.dates.map(then => moment(this.now).to(then))
},
},
mounted() {
this.interval = setInterval(() => {
this.now = new Date()
}, 1000)
}