Repair Video: MacBook Pro 15, Late 2013 Battery Replacement

For the last 10 years, or so, along with my friend Flavio I've been recording a popular Spanish-language podcast called Puromac, about all things Apple. We also have a YouTube channel which, up until recently, only had videos in Spanish. Well, I recently replaced the battery of my MacBook Pro using an iFixIt kit and made two videos about the experience: one in English and the other in Spanish. Below is the English version for your viewing pleasure:

Fed from Puromac walks us through replacing the battery on his 15" MacBook Pro, Late 2013, using a kit from iFixIt. He also shows an alternate technique for safely removing the battery pack without completely disassembling your MacBook, by using a nylon string and adhesive remover. [English Version]

Repair: Bad Electrolytic Capacitor Strikes Again, This Time In A Refrigerator Control Unit

TLDR;

My Kitchen Aid model KBLC36FMS02 built-in refrigerator had been making odd sounds for a few weeks and then one day stopped cooling. I pulled the fridge out of its niche and eventually pulled out the control board on top of condenser coil. When I Googled some of the numbers on the PCB (ex: "W10219463 control board fix"), I came across the blog of Steve Jenkins, who had an excellent post on the control board issue with all the information I needed to repair it. The problem with my control board came down to a faulty 220uf electrolytic capacitor. And as I learned from my friend Josh when I repaired a 30-year old coffee maker, electrolytic capacitors always go bad.

Details

When my refrigerator, a Kitchen Aid model KBLC36FMS02 started making odd sounds, I ignored it. A few weeks later, when it stopped cooling, I couldn't ignore it.

My first thought was that the compressor had a leaked coolant and no longer worked. I pulled the refrigerator out of its niche and took apart the enclosure on top of the fridge which housed the compressor and condenser coil.

Before taking apart the top housing, I had unplugged the refrigerator. Since I didn't see anything obviously wrong with the compressor, I plugged the fridge back in to see if that might reset the temperature sensors. The compressor started up and I saw frost appear on the output tube, so I guessed that the compressor was working correctly.

Next I took a look at the condenser coils. I thought that maybe the refrigerator had turned itself off because, if the coils were sufficiently dirty, the fridge couldn't release heat. The coils were filthy, having never been cleaned in the 10 years since the fridge had been in operation.

Dirty condenser coils

I cleaned out the coils and started up the fridge again, but it was clear after a few minutes that it still wasn't cooling. That's when I noticed that the condenser coil fan wasn't spinning. So, my next guess as to what was wrong with the fridge was that the control board, which I could see above the condenser coils, had a problem with it. I removed the board and took a look at it.

From my experience fixing a 30-year old coffee maker I learned that electrolytic capacitors often go bad. However, the capacitors on the board didn't look damaged or have any discharge like the ones I replaced in my old coffee maker.

I Googled the numbers on the PCB of the control board, hoping to find if I could find a replacement board and how much it would cost. Ebay had several services that would either sell you a new board ($850!!) or repair existing boards ($70-$200).

Then I came across Steve Jenkins' blog which had a post about the very control unit I was researching. Steve's post is excellent, with lots of useful information, including the fact that the failure condition I was experiencing is a well-known issue with the control board (model W10219463), and that two parts in particular fail on the board: a relay and an electrolytic capacitor.

From Steve's blog I learned that the single 200uf capacitor on the board is the one to go bad and when I looked at it again, I noticed that even though there was no discharge from the capacitor, its top was bulging, just like Steve described.

Bulging capacitor top

I removed the bad capacitor and tested it, confirming that it did not hold anywhere near the charge it was supposed to. 

Low capacity on bad capacitor

So, I replaced the bad 220uf capacitor with a fresh one, reinstalled the control board and started up the refrigerator. The compressor went on as did the fan! After a few minutes I confirmed that the fridge was cooling again. 

Jasmine unit testing: Don't forget to callThrough()

TL;DR

One of the great things about Jasmine, the Javascript unit testing library, is the spy. A spy lets you peek into the workings of the methods of Javascript objects. Just don't forget to use callThrough() when you don't want to alter how the spied-upon function behaves. That's because a spy automatically replaces the spied function with a stub. If you want the spied-upon function to be called normally, add .and.callThrough() to your spy statement.

Jasmine spies are great

One of the great things about Jasmine, the Javascript unit testing library, is the spy. From Jasmine's documentation:

A spy can stub any function and tracks calls to it and all arguments. A spy only exists in the describe or it block in which it is defined, and will be removed after each spec.

They are extremely useful for testing and should be part of every unit test writer's tool set. However, if you forget some basic truths about spies, you will get unexpected results and wonder why your beautiful tests don't work. Some examples:

spyOn(myGreatJSLib, 'doSomething');
myGreatJSLib.doSomething();
// passes
expect(myGreatJSLib.doSomething).toHaveBeenCalled();

spyOn(myGreatJSLib, 'doAnotherThing');
myGreatJSLib.doAnotherThing('value1', 10);
// also passes
expect(myGreatJSLib.doAnotherThing).toHaveBeenCalledWith('value1', 10);

spyOn() replaces functions

Jasmine's documentation adds:

By chaining the spy with and.callThrough, the spy will still track all calls to it but in addition it will delegate to the actual implementation.

This is an important piece of information to keep in mind, because, depending on what your testing, your tests will appear to be working correctly, but your expect statements might fail unexpectedly.

Imagine we're testing our awesome RickAndMortyLib which has a getQuote(characterName) function. Supplied with the values Rick, Morty, or Summer, the function will return a quote for that character. For the sake of this example, there is only one quote per character:

  • Rick: "Oh yeah, you gotta get schwifty."
  • Morty: "Don't even trip about your pants, dawg. We got an extra pair right here."
  • Summer: "God, Grandpa, you're such a dick."

Some examples:

spyOn(RickAndMortyLib, 'getQuote');
RickAndMortyLib.getQuote('Rick');
// passes
expect(RickAndMortyLib.getQuote).toHaveBeenCalledWith('Rick');

// but....
var rickQuote = RickAndMortyLib.getQuote('Rick');
// FAILS
expect(rickQuote).toBe('Oh yeah, you gotta get schwifty.');

Why did that last expect fail? Because the spyOn() call up top replaces getQuote() with a stub which can only confirm that it was called and/or called with specific arguments. We could fake a response with one of these two techniques:

spyOn(RickAndMortyLib, 'getQuote').and.returnValue(
                   'Morty, can you get to the left nipple?');
var rickQuote = RickAndMortyLib.getQuote('Rick');
// passes
expect(rickQuote).toBe('Morty, can you get to the left nipple?');

// or....
spyOn(RickAndMortyLib, 'getQuote').and.callFake(function() {
    return 'GRAAAAAASSSSSSS....tastes bad.'
});
// passes
expect(rickQuote).toBe('GRAAAAAASSSSSSS....tastes bad.');

Those two tests pass, and the and.returnValue() and and.callFake() calls can be very useful in situations where it's impossible or difficult to supply whatever your library needs to complete the function call on its own. However, know that you're not really testing the function itself when you use a plain spyOn() call or when you chain and.returnValue() or and.callFake().

To really test the function call itself, you need to add and.callThrough():

spyOn(RickAndMortyLib, 'getQuote').and.callThrough();
RickAndMortyLib.getQuote('Rick');
// passes
expect(RickAndMortyLib.getQuote).toHaveBeenCalledWith('Rick);
var rickQuote = RickAndMortyLib.getQuote('Rick');
// now this expect passes
expect(rickQuote).toBe('Oh yeah, you gotta get schwifty.');