When an action is atomic it means the entire action happens without interruption. For example, if I have:
This code appears to be fine. If we assume the waitForLoadingToFinish() works then this is good. However, what happens if the page loads so fast that the loading icon does not appear. So sometimes I need to wait for the icon to appear then wait for it to disappear. Other times if I wait for it to appear it never appears. The code inside waitForLoadingToFinish() is NOT atomic. It is checking for two or more events but not at once. It will check the first event, then check the second event. If something changes between the first check and the second check it could cause a deadlock or starvation (pre-emptive operating system terms) to occur. There are ways to deal with preventing deadlock or starvation but now you are making your code more difficult to maintain.
Usually what happens is you get the test to work with the timing on your development machine. When you push it to the build environment it fails because it has different timing. Or it works for one developer but not another developer. Or it works for months then you get a system update, timing changes and the test starts failing 50% of the time.
Additionally, if you don't fully understand the entire technology stack, you might have missed a scenario and the error condition still exists. The error condition might happen less frequently but this is really frustrating. If the test suite fails occasionally and it turns out to be a bad test, the developers will start to mistrust the tests. If the code is always working and the tests are occasionally failing, the developers will start trusting their coding ability and ignoring the test results.
I am Masud Parvez. Working as IT Senior Project Manager for RMIT University. Previously I built and run a distributed Test Center. My success was to turn that in to one of the most successful business units of the company.