What I've Coded This Week (Week 2—WWCode '100 Days of Code' Challenge)
Tags: webdev, programming, learning, coding
Published: 2024-01-26 18:59:04

*(Cover Image: The clock I created for the second project in the 'JavaScript30' course)*

It's time for a recap of last week!

## What I've Worked On This Week
### Quick Links
- [JavaScript—JavaScript30 Project #2: JS and CSS Clock](#javascriptjavascript30-project-2-js-and-css-clock)
- [Python—Adventures with Unit Testing](#pythonadventures-with-unit-testing)
- [React Native—Patching Packages](#react-nativepatching-packages)

### JavaScript—JavaScript30 Project #2: JS and CSS Clock
I completed the second project in [Wes Bos's JavaScript30 course](https://javascript30.com/): a clock! This exercise was an interesting challenge that gave me more experience with CSS animations (transformations and transitions), working with dates in JavaScript, and the `setInterval` function. 

I have to admit, I spent a lot of time staring at this clock, watching the minutes tick away (for debugging... but also to admire the [cubic bezier timing function](https://www.w3schools.com/cssref/func_cubic-bezier.php) that mimics the movement of physical clock hands). I thought my clock looked nice and functional as is. I hadn't even considered the possibility of adding any animation to it, but seeing the pizzazz the realistic recoil of the second hand added made me want to give it a try.

{% embed https://youtube.com/shorts/JYKndP9NmG4?feature=share
  %}

The tricky part was figuring out how to remedy the blip that occurred when a hand finished a complete rotation; it went back around to reset to its original position and then jumped back to where it was supposed to be.

{% embed https://youtube.com/shorts/PPATbRfz9WM?feature=share  %}

In his lesson, Wes said that one way to resolve this issue would be to briefly remove the `transition` property when the second hand reaches 12:00. However, I later found out that when I disabled `transition`, the `transition-timing-function` wouldn't come back automatically, so I added additional logic to my code to get that working again.

```javascript
const hands = [hourHand, minuteHand, secondHand]

if (secondDegrees === 90) {
	for (let hand of hands) hand.style.transition = "0s"
} else {
	for (let hand of hands) {
	hand.style.transition = "all 0.05s"
	hand.style.transitionTimingFunction = "cubic-bezier(0.1, 2.7, 0.58, 1)"
	}
}
```

You can see the clock, the code, and a more detailed explanation on [my GitHub](https://github.com/baspin94/JavaScript30/tree/master/02%20-%20JS%20and%20CSS%20Clock).

### Python—Adventures with Unit Testing
I've been continuing to work through the daily challenges in the WWCode Python Track and using them to get more practice with writing unit tests with Pytest. I learned a valuable lesson this week.

With the way I've been testing for exception handling in the challenges recently, my test would pass even before I'd written the corresponding code because a general `TypeError` was returned when the code failed. 
```python
def odd_or_even(integer):
	if integer % 2 == 0:
		return "Even"
	else:
		return "Odd"

def test_error():
	"""Given an invalid input, return a TypeError."""
	string = "banana"
	with pytest.raises(TypeError):
		odd_or_even(string)
```

The test passed, but when I ran the code myself using a string as an input, this was the message I received:

`TypeError: not all arguments converted during string formatting`

This message is problematic because it doesn't provide users with a clear reason why the code failed. I wanted to clarify what needs to change with the message, "Input must be an integer."

I did some research and found a very helpful resource (aside from the Pytest docs) that I will be reviewing in more detail as I continue building my unit testing skills: [Pytest with Eric](https://pytest-with-eric.com/), in particular the post, ["How To Test Python Exception Handling Using Pytest Assert (A Simple Guide)"](https://pytest-with-eric.com/introduction/pytest-assert-exception/#Understanding-Exception-Testing), which provided several examples of how to check for specific exceptions and messages.
  
From reviewing Eric's tutorial, I determined that in addition to the code I wrote above, I would need to capture the exception output in an object, `excinfo` (you could alias this object as anything you want, but this is how it is done in the official Pytest docs, too). That object has an attribute, value, which contains the error message. We'll convert that to a string to check against our desired message.

```python
def test_error():
	"""Given an invalid input, return a specific TypeError."""
	string = "banana"
	with pytest.raises(TypeError) as excinfo:
		odd_or_even(string)
	assert str(excinfo.value) == "Input must be an integer."
```

Now our test fails:

```
AssertionError: assert 'not all argu...ng formatting' == 'Input must be an integer.'

E - Input must be an integer.

E + not all arguments converted during string formatting
```

And now, we can modify the code to get that test to pass:

```python
def odd_or_even(integer):
	if type(integer) is not int:
		raise TypeError("Input must be an integer.")
	if integer % 2 == 0:
		return "Even"
	else:
	return "Odd"
```

### React Native—Patching Packages
Following up from [last week's post](https://dev.to/baspin94/what-ive-coded-this-week-week-1-wwcode-100-days-of-code-challenge-32de#react-nativerandom-acts-of-kindness-app), where my friend and I were grappling with an issue with 'React Native Reanimated', the same errors came back to haunt us again this week. I forgot that, in addition to updating the plugins in the `Babel.config.js` file (which I discussed last week), there was also a change that we'd made within the 'React Native Reanimated' node package during the troubleshooting process that also contributed to resolving that issue (thanks to this [GitHub issue](https://github.com/software-mansion/react-native-reanimated/issues/4524#issuecomment-1843947671)). 

But that could never be more than a temporary fix because:
1. Whenever we next added more packages and ran `npm install`, that tweak would get overwritten.
2. Because the `node_modules` directory is ignored by version control, anyone else installing the packages and running the code on their machine would encounter the same issue.

That's when [another GitHub issue](https://github.com/software-mansion/react-native-reanimated/issues/3614#issuecomment-1660852119) led me to the solution: the [`patch-package` library](https://www.npmjs.com/package/patch-package). Here's how I used `patch-package` to fix this issue.

1. I followed the [instructions to install the library](https://www.npmjs.com/package/patch-package) and updated "scripts" in `package.json` to run `patch-package` after each install.
```json
"scripts": {
	"postinstall": "patch-package"
 }
```
2. I went into `node_modules/react-native-reanimated/lib/module/index.web.js` and updated the export default from `export { _default as default };` to `export default _default;` as the GitHub issue conversation suggested.
3. I ran `npx patch-package react-native-reanimated`.
4. This generated a new directory, `patches`, with a patch file containing the diff for the package, that gets accessed with each `npm install`.

!['Patches' directory created in repository containing the 'React-Reanimated' patch file](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vpjl18vu6rrousiiyi6p.png)

With this issue now put back to bed, I'm looking forward to doing a deep dive into [React Native Calendars](https://wix.github.io/react-native-calendars/) over this next week.

## Looking Ahead
That's a wrap for this week! 

Here's what's in the works ahead of next week:
- Continuing to explore React Native Calendars
- Continuing JavaScript30 and Python Daily Challenges
- Starting [Kevin Powell's Responsive Design Course](https://courses.kevinpowell.co/conquering-responsive-layouts)

I'll check in again next week to let you know how it all goes—stay tuned!